{
 "cells": [
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "%env LLM_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1\n",
    "%env LLM_API_KEY=sk-替换为自己的key"
   ],
   "id": "8d40ed134ccc30fd"
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "af375836-b870-458b-87d1-4e00565977eb",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:35:54.528066Z",
     "iopub.status.busy": "2025-02-27T14:35:54.527935Z",
     "iopub.status.idle": "2025-02-27T14:35:54.538889Z",
     "shell.execute_reply": "2025-02-27T14:35:54.538462Z",
     "shell.execute_reply.started": "2025-02-27T14:35:54.528053Z"
    },
    "papermill": {
     "duration": 0.115454,
     "end_time": "2024-11-23T14:29:00.919641",
     "exception": false,
     "start_time": "2024-11-23T14:29:00.804187",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "%%capture --no-stderr\n",
    "!pip install -U langchain langchain-community langchain-openai langchain_chroma pypdf sentence_transformers shutil openpyxl FlagEmbedding"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "1e2c72b8-ee12-4130-af88-699998aa230c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:35:54.539566Z",
     "iopub.status.busy": "2025-02-27T14:35:54.539443Z",
     "iopub.status.idle": "2025-02-27T14:35:54.747586Z",
     "shell.execute_reply": "2025-02-27T14:35:54.747091Z",
     "shell.execute_reply.started": "2025-02-27T14:35:54.539554Z"
    },
    "papermill": {
     "duration": 0.319981,
     "end_time": "2024-11-23T14:29:01.380771",
     "exception": false,
     "start_time": "2024-11-23T14:29:01.060790",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "import os\n",
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "d29a8d77-bea4-40d5-86cc-6cacdafbe702",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:35:54.748285Z",
     "iopub.status.busy": "2025-02-27T14:35:54.748101Z",
     "iopub.status.idle": "2025-02-27T14:35:54.750683Z",
     "shell.execute_reply": "2025-02-27T14:35:54.750362Z",
     "shell.execute_reply.started": "2025-02-27T14:35:54.748272Z"
    }
   },
   "outputs": [],
   "source": [
    "import sys"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "655f9dc5-a5fe-424d-94ed-f096f29cf3f7",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:35:54.751293Z",
     "iopub.status.busy": "2025-02-27T14:35:54.751172Z",
     "iopub.status.idle": "2025-02-27T14:35:54.762440Z",
     "shell.execute_reply": "2025-02-27T14:35:54.761900Z",
     "shell.execute_reply.started": "2025-02-27T14:35:54.751281Z"
    }
   },
   "outputs": [],
   "source": [
    "sys.path.append('late-chunking')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "841d2b02-ad06-40d2-b11f-c7adccec6ca2",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:35:54.763088Z",
     "iopub.status.busy": "2025-02-27T14:35:54.762923Z",
     "iopub.status.idle": "2025-02-27T14:35:54.877049Z",
     "shell.execute_reply": "2025-02-27T14:35:54.876582Z",
     "shell.execute_reply.started": "2025-02-27T14:35:54.763077Z"
    },
    "papermill": {
     "duration": 0.121409,
     "end_time": "2024-11-23T14:29:01.638126",
     "exception": false,
     "start_time": "2024-11-23T14:29:01.516717",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "expr_version = 'split_05_late_chunking'\n",
    "\n",
    "preprocess_output_dir = os.path.join(os.path.pardir, 'outputs', 'v1_20240713')\n",
    "qa_df = pd.read_excel(os.path.join(preprocess_output_dir, 'question_answer.xlsx'))\n",
    "expr_dir = os.path.join(os.path.pardir, 'experiments', expr_version)\n",
    "\n",
    "os.makedirs(expr_dir, exist_ok=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cf7e81e3-4c82-4842-aef5-7592caaf1d39",
   "metadata": {
    "papermill": {
     "duration": 0.100379,
     "end_time": "2024-11-23T14:29:01.862379",
     "exception": false,
     "start_time": "2024-11-23T14:29:01.762000",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "# 读取文档"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "e6920e29-bc7d-4635-be06-d151eaf0e100",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:35:54.878345Z",
     "iopub.status.busy": "2025-02-27T14:35:54.878181Z",
     "iopub.status.idle": "2025-02-27T14:35:56.541683Z",
     "shell.execute_reply": "2025-02-27T14:35:56.541206Z",
     "shell.execute_reply.started": "2025-02-27T14:35:54.878332Z"
    },
    "papermill": {
     "duration": 2.012298,
     "end_time": "2024-11-23T14:29:03.974974",
     "exception": false,
     "start_time": "2024-11-23T14:29:01.962676",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from langchain_community.document_loaders import PyPDFLoader\n",
    "import re\n",
    "\n",
    "loader = PyPDFLoader(os.path.join(os.path.pardir, 'data', '2024全球经济金融展望报告.pdf'))\n",
    "pdf_documents = loader.load()\n",
    "\n",
    "# 把页眉页脚去掉\n",
    "pattern = r\"^全球经济金融展望报告\\n中国银行研究院 \\d+ 2024年\"\n",
    "# PyPDFLoader解析的文档\n",
    "pdf_document = '\\n\\n'.join(re.sub(pattern, '', doc.page_content) for doc in pdf_documents)\n",
    "# MinerU解析的文档\n",
    "markdown_document = open(os.path.join(os.path.pardir, 'outputs', 'MinerU_parsed_20241204', '2024全球经济金融展望报告.md')).read()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "575f15d5-8035-4451-9385-9acecac6bdf5",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:35:56.542340Z",
     "iopub.status.busy": "2025-02-27T14:35:56.542208Z",
     "iopub.status.idle": "2025-02-27T14:35:56.546368Z",
     "shell.execute_reply": "2025-02-27T14:35:56.546061Z",
     "shell.execute_reply.started": "2025-02-27T14:35:56.542327Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "31202"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(pdf_document)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "b77b8fd4-38c3-4c8d-b913-d80926d6fb84",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:35:56.546905Z",
     "iopub.status.busy": "2025-02-27T14:35:56.546784Z",
     "iopub.status.idle": "2025-02-27T14:35:56.559640Z",
     "shell.execute_reply": "2025-02-27T14:35:56.559336Z",
     "shell.execute_reply.started": "2025-02-27T14:35:56.546894Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "33940"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(markdown_document)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "841ec659-4ad7-4e1f-b1ea-3477bf97fde3",
   "metadata": {
    "papermill": {
     "duration": 0.100297,
     "end_time": "2024-11-23T14:29:04.219302",
     "exception": false,
     "start_time": "2024-11-23T14:29:04.119005",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "# 文档切分"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "74fe856a-7c19-4c3c-bb30-7abfa6298f74",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:35:56.561752Z",
     "iopub.status.busy": "2025-02-27T14:35:56.561471Z",
     "iopub.status.idle": "2025-02-27T14:35:56.724412Z",
     "shell.execute_reply": "2025-02-27T14:35:56.723911Z",
     "shell.execute_reply.started": "2025-02-27T14:35:56.561740Z"
    },
    "papermill": {
     "duration": 0.109229,
     "end_time": "2024-11-23T14:29:04.429069",
     "exception": false,
     "start_time": "2024-11-23T14:29:04.319840",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "import os\n",
    "import pickle\n",
    "import requests\n",
    "from langchain.schema import Document"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "2aee1771-7302-43f7-ad65-8f2ecafd06d5",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:36:02.466464Z",
     "iopub.status.busy": "2025-02-27T14:36:02.465898Z",
     "iopub.status.idle": "2025-02-27T14:36:02.473856Z",
     "shell.execute_reply": "2025-02-27T14:36:02.471851Z",
     "shell.execute_reply.started": "2025-02-27T14:36:02.466416Z"
    }
   },
   "outputs": [],
   "source": "model_path = 'BAAI/bge-m3'"
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "41c6580c-c01a-4801-ad75-e35eef8ece05",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:36:03.570579Z",
     "iopub.status.busy": "2025-02-27T14:36:03.569765Z",
     "iopub.status.idle": "2025-02-27T14:36:08.312243Z",
     "shell.execute_reply": "2025-02-27T14:36:08.311731Z",
     "shell.execute_reply.started": "2025-02-27T14:36:03.570509Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "device: cuda\n"
     ]
    }
   ],
   "source": [
    "from transformers import AutoModel, AutoTokenizer\n",
    "import torch\n",
    "import json\n",
    "import torch.nn.functional as F\n",
    "\n",
    "device = 'cuda' if torch.cuda.is_available() else 'cpu'\n",
    "print(f'device: {device}')\n",
    "\n",
    "# load model and tokenizer\n",
    "tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)\n",
    "model = AutoModel.from_pretrained(model_path, trust_remote_code=True, device_map=device)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b14c60e2-9097-488c-8d09-8e88b3016891",
   "metadata": {},
   "source": [
    "- 原文：https://jina.ai/news/late-chunking-in-long-context-embedding-models/\n",
    "- 代码：https://colab.research.google.com/drive/15vNZb6AsU7byjYoaEtXuNu567JWNzXOz?usp=sharing"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "ab1a6e82-908d-40ce-b6a5-3d4923944bf2",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:36:10.292023Z",
     "iopub.status.busy": "2025-02-27T14:36:10.291724Z",
     "iopub.status.idle": "2025-02-27T14:36:10.301345Z",
     "shell.execute_reply": "2025-02-27T14:36:10.300966Z",
     "shell.execute_reply.started": "2025-02-27T14:36:10.292008Z"
    }
   },
   "outputs": [],
   "source": [
    "from tqdm.auto import trange\n",
    "import numpy as np\n",
    "\n",
    "# 这个方法来自：https://github.com/weaviate/late-chunking-experiments/blob/main/late_chunking.ipynb\n",
    "def chunk_by_tokens(input_text: str, tokenizer: callable, chunk_size: int = 512):\n",
    "    \"\"\"\n",
    "    Split the input text into chunks of approximately chunk_size tokens\n",
    "    \"\"\"\n",
    "    tokens = tokenizer(input_text, return_offsets_mapping=True, add_special_tokens=False)\n",
    "    token_offsets = tokens['offset_mapping']\n",
    "    \n",
    "    chunks = []\n",
    "    span_annotations = []\n",
    "    \n",
    "    for i in range(0, len(token_offsets), chunk_size):\n",
    "        chunk_end = min(i + chunk_size, len(token_offsets))\n",
    "        if chunk_end - i > 0:\n",
    "            start_offset = token_offsets[i][0]\n",
    "            end_offset = token_offsets[chunk_end - 1][1]\n",
    "            chunks.append(input_text[start_offset:end_offset])\n",
    "            span_annotations.append((i, chunk_end))\n",
    "    \n",
    "    return chunks, span_annotations\n",
    "\n",
    "def chunk_by_sentences(input_text: str, tokenizer: callable):\n",
    "    \"\"\"\n",
    "    Split the input text into sentences using the tokenizer\n",
    "    :param input_text: The text snippet to split into sentences\n",
    "    :param tokenizer: The tokenizer to use\n",
    "    :return: A tuple containing the list of text chunks and their corresponding token spans\n",
    "    \"\"\"\n",
    "    inputs = tokenizer(input_text, return_tensors='pt', return_offsets_mapping=True)\n",
    "    punctuation_mark_ids = [tokenizer.convert_tokens_to_ids(punc) for punc in ('。', '？', '！')]\n",
    "    sep_id = tokenizer.convert_tokens_to_ids('[SEP]')\n",
    "    token_offsets = inputs['offset_mapping'][0]\n",
    "    token_ids = inputs['input_ids'][0]\n",
    "    chunk_positions = [\n",
    "        (i, int(start + 1))\n",
    "        for i, (token_id, (start, end)) in enumerate(zip(token_ids, token_offsets))\n",
    "        if token_id in punctuation_mark_ids\n",
    "        and (\n",
    "            token_offsets[i + 1][0] - token_offsets[i][1] > 0\n",
    "            or token_ids[i + 1] == sep_id\n",
    "        )\n",
    "    ]\n",
    "    chunks = [\n",
    "        input_text[x[1] : y[1]]\n",
    "        for x, y in zip([(1, 0)] + chunk_positions[:-1], chunk_positions)\n",
    "    ]\n",
    "    span_annotations = [\n",
    "        (x[0], y[0]) for (x, y) in zip([(1, 0)] + chunk_positions[:-1], chunk_positions)\n",
    "    ]\n",
    "    return chunks, span_annotations\n",
    "\n",
    "def document_to_token_embeddings(model, tokenizer, document, batch_size=4096):\n",
    "    tokenized_document = tokenizer(document, return_tensors=\"pt\")\n",
    "    tokens = tokenized_document.tokens()\n",
    "\n",
    "    outputs = []\n",
    "    for i in trange(0, len(tokens), batch_size):\n",
    "        \n",
    "        start = i\n",
    "        end   = min(i + batch_size, len(tokens))\n",
    "\n",
    "        batch_inputs = {k: v[:, start:end].to(device) for k, v in tokenized_document.items()}\n",
    "\n",
    "        with torch.no_grad():\n",
    "            model_output = model(**batch_inputs)\n",
    "\n",
    "        outputs.append(model_output.last_hidden_state)\n",
    "\n",
    "    model_output = torch.cat(outputs, dim=1)\n",
    "    return model_output\n",
    "\n",
    "def late_chunking(token_embeddings, span_annotation, max_length=None):\n",
    "    outputs = []\n",
    "    for embeddings, annotations in zip(token_embeddings, span_annotation):\n",
    "        if (max_length is not None):\n",
    "            annotations = [\n",
    "                (start, min(end, max_length - 1))\n",
    "                for (start, end) in annotations\n",
    "                if start < (max_length - 1)\n",
    "            ]\n",
    "        pooled_embeddings = []\n",
    "\n",
    "        for idx, (start, end) in enumerate(annotations):\n",
    "            assert chunks[idx] == tokenizer.decode(doc_input_ids[start: end]), f\"idx={idx}, (start, end)={(start, end)}, chunks[idx]={chunks[idx]}, tokenizer.decode(doc_input_ids[start: end])={tokenizer.decode(doc_input_ids[start: end])}\"\n",
    "            if (end - start) >= 1:\n",
    "                pooled_embeddings.append(\n",
    "                    # embeddings[start:end].sum(dim=0) / (end - start)\n",
    "                    embeddings[start:end].mean(dim=0).cpu().numpy()\n",
    "                )\n",
    "            else:\n",
    "                raise ValueError()\n",
    "                   \n",
    "        pooled_embeddings = [\n",
    "            embedding / np.linalg.norm(embedding) for embedding in pooled_embeddings\n",
    "        ]\n",
    "        outputs.append(pooled_embeddings)\n",
    "    return outputs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "4f711918-5a3b-49e8-a1a9-be38813a9a34",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:37:22.791154Z",
     "iopub.status.busy": "2025-02-27T14:37:22.790355Z",
     "iopub.status.idle": "2025-02-27T14:37:22.799355Z",
     "shell.execute_reply": "2025-02-27T14:37:22.797198Z",
     "shell.execute_reply.started": "2025-02-27T14:37:22.791081Z"
    }
   },
   "outputs": [],
   "source": [
    "# debug begin 由于总体切分逻辑相对复杂，下面对这个过程进行调试，检查切分逻辑"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "afa5936f-5f08-45c7-b361-db909a72c8ab",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:37:22.985213Z",
     "iopub.status.busy": "2025-02-27T14:37:22.985038Z",
     "iopub.status.idle": "2025-02-27T14:37:23.068362Z",
     "shell.execute_reply": "2025-02-27T14:37:23.067909Z",
     "shell.execute_reply.started": "2025-02-27T14:37:22.985199Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Token indices sequence length is longer than the specified maximum sequence length for this model (20751 > 8192). Running this sequence through the model will result in indexing errors\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "40"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain.text_splitter import RecursiveCharacterTextSplitter\n",
    "\n",
    "splitter = RecursiveCharacterTextSplitter(\n",
    "    chunk_size=1024,\n",
    "    chunk_overlap=0,\n",
    "    separators=['\\n\\n\\n', '\\n\\n']\n",
    ")\n",
    "# chunks = splitter.split_text(pdf_document)\n",
    "chunks = splitter.split_text(markdown_document)\n",
    "chunks = [tokenizer.decode(tokenizer(text.strip(), return_tensors='pt')['input_ids'][0, 1:-1]) for text in chunks]\n",
    "processed_doc = '\\n\\n'.join(chunks)\n",
    "doc_tokens = tokenizer(processed_doc, return_tensors='pt')\n",
    "\n",
    "len(chunks)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "53e9ac66-0769-4a3a-9c4c-52d1a961c036",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:37:23.666081Z",
     "iopub.status.busy": "2025-02-27T14:37:23.665847Z",
     "iopub.status.idle": "2025-02-27T14:37:23.700114Z",
     "shell.execute_reply": "2025-02-27T14:37:23.699694Z",
     "shell.execute_reply.started": "2025-02-27T14:37:23.666065Z"
    }
   },
   "outputs": [],
   "source": [
    "span_annotations = []\n",
    "\n",
    "doc_input_ids = doc_tokens['input_ids'][0]\n",
    "start_pos = 1\n",
    "seperator_len = len(tokenizer('\\n\\n', return_tensors='pt')['input_ids'][0]) - 2\n",
    "\n",
    "for chunk_idx, chunk in enumerate(chunks):\n",
    "    # 1: -1排除首位的<s></s>\n",
    "    chunk_input_ids = tokenizer(chunk, return_tensors='pt')['input_ids'][0][1:-1]\n",
    "    chunk_token_len = len(chunk_input_ids)\n",
    "    # 有时候chunk_input_ids decode开头2位都不是实际文本\n",
    "    if (doc_input_ids[start_pos: start_pos + chunk_token_len] == chunk_input_ids).detach().numpy().mean() != 1:\n",
    "        start_pos += 1\n",
    "    \n",
    "    assert (doc_input_ids[start_pos: start_pos + chunk_token_len] == chunk_input_ids).detach().numpy().mean() == 1, chunk_idx\n",
    "    span_annotations.append((start_pos, start_pos + chunk_token_len))\n",
    "    start_pos += chunk_token_len"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "31bb66fa-8bfe-4c1d-b5b2-13b0f81632aa",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:37:25.309460Z",
     "iopub.status.busy": "2025-02-27T14:37:25.309277Z",
     "iopub.status.idle": "2025-02-27T14:37:25.312522Z",
     "shell.execute_reply": "2025-02-27T14:37:25.312132Z",
     "shell.execute_reply.started": "2025-02-27T14:37:25.309445Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "40"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(span_annotations)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "bf379ab8-42dc-47ec-9d77-518d2cfb3388",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:37:25.788142Z",
     "iopub.status.busy": "2025-02-27T14:37:25.787362Z",
     "iopub.status.idle": "2025-02-27T14:37:25.793154Z",
     "shell.execute_reply": "2025-02-27T14:37:25.792784Z",
     "shell.execute_reply.started": "2025-02-27T14:37:25.788074Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(11849, 12435)"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "span_annotations[23]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "feb11aa0-4aee-4a44-a4cd-c10bfca1447a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:37:26.301537Z",
     "iopub.status.busy": "2025-02-27T14:37:26.300742Z",
     "iopub.status.idle": "2025-02-27T14:37:26.307626Z",
     "shell.execute_reply": "2025-02-27T14:37:26.307228Z",
     "shell.execute_reply.started": "2025-02-27T14:37:26.301467Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'2024年,跨境资本流动可能将发生趋势性变化,跨境资本回流美国态势会进一步放缓。惠誉、穆迪下调美债信用评级或评级展望将影响跨境资本回流美国的趋势,投资者增持美债的意愿降低。欧元区将延续资本净流出态势,FDI和银行主导的其他投资仍可能成为欧元区资本外流的主要推动力量。随着负利率政策结束,日本跨境资本净流出下降,证券投资和其他投资净流出或将减少。跨境资金流向新兴经济体的节奏有望提速,流向新兴经济体的资金仍将以组合投资、其他投资为主导。 # (三)汇率市场:美元指数高位震荡后走弱,新兴市场货币币值小幅回升 2023年以来,美元指数始终保持高位,在100-105区间波动,7月初开始震荡走高,之后逐渐从高位回落。受美联储货币政策影响,2023年11月15日,美元指数为104.4,较年初上涨 $0.6\\\\%$ (图17)。主要发达经济体货币汇率走势涨跌不一。2023年欧元和英镑兑美元汇率均呈现宽幅震荡态势,与年初相比欧元和英镑分别小幅升值 $1.4\\\\%$ 、 $2.8\\\\%$ ;日元币值持续走低,贬值幅度达 $13.3\\\\%$ ;瑞士法郎在震荡中升值 $4.2\\\\%$ 。美元升值背景下,新兴经济体货币遭受冲击。截至11月15日,俄罗斯卢布、土耳其里拉和阿根廷比索跌幅分别高达 $18.2\\\\%$ 、 $34.8\\\\%$ 、 $49.9\\\\%$,面临较大的汇率波动风险(图18)。![](images/505b072a246f1b79dcd689ed41c1771a377cfbb6b84ce33a9c4e7f7a453f5856.jpg) 图17:2023年美元指数变动趋势 资料来源:Wind,中国银行研究院![](images/39e12dda59e8e920ae43789e542c89192b924c2bc9a807c73786be598affa3cd.jpg) 图18:主要货币兑美元汇率较2023年年初变动 $(\\\\%)$ ) 注:数据截至2023年11月15日。 资料来源:Wind,中国银行研究院展望2024年,全球汇率市场走势主要呈现以下特征。 # 1.美元在保持一段时间强势后走弱,欧元英镑仍维持区间震荡'"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tokenizer.decode(doc_input_ids[span_annotations[23][0]:span_annotations[23][1]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "0c7d231d-bab4-4e1f-8b14-757eb2dca230",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:37:26.724618Z",
     "iopub.status.busy": "2025-02-27T14:37:26.723827Z",
     "iopub.status.idle": "2025-02-27T14:37:26.730348Z",
     "shell.execute_reply": "2025-02-27T14:37:26.730029Z",
     "shell.execute_reply.started": "2025-02-27T14:37:26.724548Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'2024年,跨境资本流动可能将发生趋势性变化,跨境资本回流美国态势会进一步放缓。惠誉、穆迪下调美债信用评级或评级展望将影响跨境资本回流美国的趋势,投资者增持美债的意愿降低。欧元区将延续资本净流出态势,FDI和银行主导的其他投资仍可能成为欧元区资本外流的主要推动力量。随着负利率政策结束,日本跨境资本净流出下降,证券投资和其他投资净流出或将减少。跨境资金流向新兴经济体的节奏有望提速,流向新兴经济体的资金仍将以组合投资、其他投资为主导。 # (三)汇率市场:美元指数高位震荡后走弱,新兴市场货币币值小幅回升 2023年以来,美元指数始终保持高位,在100-105区间波动,7月初开始震荡走高,之后逐渐从高位回落。受美联储货币政策影响,2023年11月15日,美元指数为104.4,较年初上涨 $0.6\\\\%$ (图17)。主要发达经济体货币汇率走势涨跌不一。2023年欧元和英镑兑美元汇率均呈现宽幅震荡态势,与年初相比欧元和英镑分别小幅升值 $1.4\\\\%$ 、 $2.8\\\\%$ ;日元币值持续走低,贬值幅度达 $13.3\\\\%$ ;瑞士法郎在震荡中升值 $4.2\\\\%$ 。美元升值背景下,新兴经济体货币遭受冲击。截至11月15日,俄罗斯卢布、土耳其里拉和阿根廷比索跌幅分别高达 $18.2\\\\%$ 、 $34.8\\\\%$ 、 $49.9\\\\%$,面临较大的汇率波动风险(图18)。![](images/505b072a246f1b79dcd689ed41c1771a377cfbb6b84ce33a9c4e7f7a453f5856.jpg) 图17:2023年美元指数变动趋势 资料来源:Wind,中国银行研究院![](images/39e12dda59e8e920ae43789e542c89192b924c2bc9a807c73786be598affa3cd.jpg) 图18:主要货币兑美元汇率较2023年年初变动 $(\\\\%)$ ) 注:数据截至2023年11月15日。 资料来源:Wind,中国银行研究院展望2024年,全球汇率市场走势主要呈现以下特征。 # 1.美元在保持一段时间强势后走弱,欧元英镑仍维持区间震荡'"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chunks[23]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "a2b1f3d7-e6d1-495d-a074-b466f5cd06e3",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:37:28.166391Z",
     "iopub.status.busy": "2025-02-27T14:37:28.165552Z",
     "iopub.status.idle": "2025-02-27T14:37:28.174459Z",
     "shell.execute_reply": "2025-02-27T14:37:28.172096Z",
     "shell.execute_reply.started": "2025-02-27T14:37:28.166320Z"
    }
   },
   "outputs": [],
   "source": [
    "# debug end"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dc73a8cb-4eb3-49f8-a33f-16f3d1ea0454",
   "metadata": {},
   "source": [
    "整篇文档的Embedding"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "9d08c9dd-5e86-4005-ab0b-3f560e392637",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:37:29.269648Z",
     "iopub.status.busy": "2025-02-27T14:37:29.268848Z",
     "iopub.status.idle": "2025-02-27T14:37:31.750950Z",
     "shell.execute_reply": "2025-02-27T14:37:31.750432Z",
     "shell.execute_reply.started": "2025-02-27T14:37:29.269578Z"
    }
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "c350eb27d80a4cc4a929b774447934a8",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/21 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "document_embeddings = document_to_token_embeddings(model, tokenizer, processed_doc, batch_size=1024)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "39ab15ae-2f8b-4b06-9b7e-b3a003852507",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:37:44.166838Z",
     "iopub.status.busy": "2025-02-27T14:37:44.166650Z",
     "iopub.status.idle": "2025-02-27T14:37:44.170399Z",
     "shell.execute_reply": "2025-02-27T14:37:44.169872Z",
     "shell.execute_reply.started": "2025-02-27T14:37:44.166824Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "20751"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(document_embeddings[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "258ab96c-a5a5-4654-bbea-dbe96f349b36",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:37:47.067016Z",
     "iopub.status.busy": "2025-02-27T14:37:47.066653Z",
     "iopub.status.idle": "2025-02-27T14:37:47.088021Z",
     "shell.execute_reply": "2025-02-27T14:37:47.087548Z",
     "shell.execute_reply.started": "2025-02-27T14:37:47.066986Z"
    }
   },
   "outputs": [],
   "source": [
    "late_embeddings = late_chunking(document_embeddings, [span_annotations])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "220dbc3a-fceb-4e49-a3f1-01e16660b2a6",
   "metadata": {
    "papermill": {
     "duration": 0.100209,
     "end_time": "2024-11-23T14:29:05.255871",
     "exception": false,
     "start_time": "2024-11-23T14:29:05.155662",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "# 检索"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d113d1b6-990f-4582-b557-711f9e59b612",
   "metadata": {},
   "source": [
    "此处为了兼容Chroma想粮库逻辑，直接根据片段查找已经Late Chunking好的向量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "cb1a96ce-8f6b-4f4d-8945-36e9c1863b39",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:38:51.465148Z",
     "iopub.status.busy": "2025-02-27T14:38:51.464370Z",
     "iopub.status.idle": "2025-02-27T14:38:51.483587Z",
     "shell.execute_reply": "2025-02-27T14:38:51.481216Z",
     "shell.execute_reply.started": "2025-02-27T14:38:51.465080Z"
    }
   },
   "outputs": [],
   "source": [
    "from langchain_core.embeddings import Embeddings\n",
    "\n",
    "class CustomEmbeddingFn(Embeddings):\n",
    "    def embed_documents(self, texts: list[str]) -> list[list[float]]:\n",
    "        ret = []\n",
    "        for text in texts:\n",
    "            idx = chunks.index(text)\n",
    "            ret.append(late_embeddings[0][idx])\n",
    "            # ret.append(self.embed_query(text))\n",
    "\n",
    "        assert len(ret) == len(texts)\n",
    "        return ret\n",
    "\n",
    "    def embed_query(self, text: str) -> list[float]:\n",
    "        tokenized_document = tokenizer(text, return_tensors=\"pt\").to(device)\n",
    "        with torch.no_grad():\n",
    "            model_output = model(**tokenized_document)\n",
    "        # (bz, seq_len, emb_sz)\n",
    "        hidden_states = model_output.last_hidden_state\n",
    "        hidden_states = hidden_states[0]\n",
    "        emb = hidden_states[1:-1].sum(dim=0) / (len(hidden_states))\n",
    "        emb /= torch.norm(emb)\n",
    "        return emb.cpu().numpy()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "8e34ea5a-a3e5-46fd-9bdc-ad2fe902ad85",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:38:52.882022Z",
     "iopub.status.busy": "2025-02-27T14:38:52.881201Z",
     "iopub.status.idle": "2025-02-27T14:38:52.891054Z",
     "shell.execute_reply": "2025-02-27T14:38:52.888733Z",
     "shell.execute_reply.started": "2025-02-27T14:38:52.881925Z"
    }
   },
   "outputs": [],
   "source": [
    "cust_emb_fn = CustomEmbeddingFn()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "aa5c716a-e88a-474d-8fc7-dc8fd237deb2",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:38:53.124441Z",
     "iopub.status.busy": "2025-02-27T14:38:53.123665Z",
     "iopub.status.idle": "2025-02-27T14:38:53.137186Z",
     "shell.execute_reply": "2025-02-27T14:38:53.135006Z",
     "shell.execute_reply.started": "2025-02-27T14:38:53.124374Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'# 全球经济金融展望报告 2024年年报(总第57期) 报告日期:2023年12月12日 # 要点 ●2023 年全球经济增长动力持续回落,各国复苏分化,发达经济体增速明显放缓,新兴经济体整体表现稳定。全球贸易增长乏力,各国生产景气度逐渐回落,内需对经济的拉动作用减弱。欧美央行货币政策紧缩态势放缓,美元指数高位震荡后走弱,全球股市表现总体好于预期,但区域分化明显。高利率环境抑制债券融资需求,债券违约风险持续上升。 $\\\\bullet$ 展望2024 年,预计全球经济复苏将依旧疲软,主要经济体增长态势和货币政策走势将进一步分化。欧美央行大概率结束本轮紧缩货币周期,美元指数将逐步走弱,流向新兴经济体的跨境资本将增加。国际原油市场短缺格局或延续,新能源发展成为重点。 $\\\\bullet$ 海湾六国经济发展与投资前景、高利率和高债务对美国房地产市场脆弱性的影响等热点问题值得关注。![](images/c7e6ce1606712e84e07a05bcf6016906efa3fc778e40fcd0e91ac4fcb5503b79.jpg) 主要经济体GDP 增速变化趋势(%) 资料来源:IMF,中国银行研究院 # 中国银行研究院全球经济金融研究课题组![](images/a5d0eb181c75231451c8f890ec50fe5822e2306a9beb543ca35a04880abbf639.jpg) 联系人:王有鑫 电话:010-66594127 邮件: wangyouxin_hq@bank-of-china.com # 全球经济复苏疲软,货币政策取向分化 ——中国银行全球经济金融展望报告(2024年)'"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chunks[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "601f6243-dd4f-451d-be0b-0c4df5436130",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:38:54.232594Z",
     "iopub.status.busy": "2025-02-27T14:38:54.231805Z",
     "iopub.status.idle": "2025-02-27T14:38:54.238267Z",
     "shell.execute_reply": "2025-02-27T14:38:54.237952Z",
     "shell.execute_reply.started": "2025-02-27T14:38:54.232526Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-0.01493518,  0.02493956, -0.01642812, ..., -0.00148642,\n",
       "       -0.01115633, -0.02175757], dtype=float32)"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "late_embeddings[0][0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "2b8dbc18-cc95-42da-b97e-482f11577a7f",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:38:54.726855Z",
     "iopub.status.busy": "2025-02-27T14:38:54.726079Z",
     "iopub.status.idle": "2025-02-27T14:38:54.732831Z",
     "shell.execute_reply": "2025-02-27T14:38:54.732383Z",
     "shell.execute_reply.started": "2025-02-27T14:38:54.726786Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[array([-0.01493518,  0.02493956, -0.01642812, ..., -0.00148642,\n",
       "        -0.01115633, -0.02175757], dtype=float32)]"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cust_emb_fn.embed_documents([chunks[0]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "edd539fb-aa86-4364-ac27-30d3493bb52e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:38:55.959015Z",
     "iopub.status.busy": "2025-02-27T14:38:55.958845Z",
     "iopub.status.idle": "2025-02-27T14:38:56.045319Z",
     "shell.execute_reply": "2025-02-27T14:38:56.044802Z",
     "shell.execute_reply.started": "2025-02-27T14:38:55.959002Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-0.01151318,  0.02350147, -0.01801374, ...,  0.01589576,\n",
       "       -0.00841782, -0.01799052], dtype=float32)"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cust_emb_fn.embed_query(chunks[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "b181264b-1ba0-4149-9111-c68dd2592f0c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:38:56.254509Z",
     "iopub.status.busy": "2025-02-27T14:38:56.253703Z",
     "iopub.status.idle": "2025-02-27T14:38:56.317169Z",
     "shell.execute_reply": "2025-02-27T14:38:56.316583Z",
     "shell.execute_reply.started": "2025-02-27T14:38:56.254441Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.97216177"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.dot(late_embeddings[0][0], cust_emb_fn.embed_query(chunks[0]).T)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "d36af462-e3bf-4312-baa8-e025e9883fd2",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:39:12.302840Z",
     "iopub.status.busy": "2025-02-27T14:39:12.302625Z",
     "iopub.status.idle": "2025-02-27T14:39:26.795657Z",
     "shell.execute_reply": "2025-02-27T14:39:26.793227Z",
     "shell.execute_reply.started": "2025-02-27T14:39:12.302827Z"
    }
   },
   "outputs": [],
   "source": [
    "from langchain.vectorstores import Chroma\n",
    "import shutil\n",
    "\n",
    "persist_directory = os.path.join(expr_dir, 'chroma', 'late_chunking')\n",
    "shutil.rmtree(persist_directory, ignore_errors=True)\n",
    "os.makedirs(persist_directory, exist_ok=True)\n",
    "\n",
    "vector_db = Chroma.from_texts(\n",
    "    chunks,\n",
    "    embedding=CustomEmbeddingFn(),\n",
    "    persist_directory=persist_directory\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7925564a-7d30-4914-baaf-4a00abb7686d",
   "metadata": {
    "papermill": {
     "duration": 0.109216,
     "end_time": "2024-11-23T14:35:26.464009",
     "exception": false,
     "start_time": "2024-11-23T14:35:26.354793",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "# 生成答案"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "27132c3b-0051-4df6-bf57-fd804acb8d17",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:40:46.258920Z",
     "iopub.status.busy": "2025-02-27T14:40:46.258128Z",
     "iopub.status.idle": "2025-02-27T14:40:46.350987Z",
     "shell.execute_reply": "2025-02-27T14:40:46.350474Z",
     "shell.execute_reply.started": "2025-02-27T14:40:46.258851Z"
    },
    "papermill": {
     "duration": 0.199165,
     "end_time": "2024-11-23T14:35:27.323500",
     "exception": false,
     "start_time": "2024-11-23T14:35:27.124335",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/ipykernel_2513129/3342461511.py:3: LangChainDeprecationWarning: The class `Ollama` was deprecated in LangChain 0.3.1 and will be removed in 1.0.0. An updated version of the class exists in the :class:`~langchain-ollama package and should be used instead. To use it run `pip install -U :class:`~langchain-ollama` and import as `from :class:`~langchain_ollama import OllamaLLM``.\n",
      "  ollama_llm = Ollama(\n"
     ]
    }
   ],
   "source": [
    "from langchain.llms import Ollama\n",
    "\n",
    "ollama_llm = Ollama(\n",
    "    model='qwen2:7b-instruct',\n",
    "    base_url='http://localhost:11434',\n",
    "    top_k=1\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "50404beb-3be0-4aaa-b124-8c7a52b84531",
   "metadata": {
    "editable": true,
    "execution": {
     "iopub.execute_input": "2025-02-27T14:40:47.168459Z",
     "iopub.status.busy": "2025-02-27T14:40:47.167210Z",
     "iopub.status.idle": "2025-02-27T14:40:47.174412Z",
     "shell.execute_reply": "2025-02-27T14:40:47.173866Z",
     "shell.execute_reply.started": "2025-02-27T14:40:47.168383Z"
    },
    "papermill": {
     "duration": 0.159318,
     "end_time": "2024-11-23T14:35:26.768506",
     "exception": false,
     "start_time": "2024-11-23T14:35:26.609188",
     "status": "completed"
    },
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "import time\n",
    "\n",
    "def rag(vector_db, llm, query, n_chunks=4):\n",
    "    prompt_tmpl = \"\"\"\n",
    "你是一个金融分析师，擅长根据所获取的信息片段，对问题进行分析和推理。\n",
    "你的任务是根据所获取的信息片段（<<<<context>>><<<</context>>>之间的内容）回答问题。\n",
    "回答保持简洁，不必重复问题，不要添加描述性解释和与答案无关的任何内容。\n",
    "已知信息：\n",
    "<<<<context>>>\n",
    "{{knowledge}}\n",
    "<<<</context>>>\n",
    "\n",
    "问题：{{query}}\n",
    "请回答：\n",
    "\"\"\".strip()\n",
    "    chunks = vector_db.similarity_search(query, k=n_chunks)\n",
    "    prompt = prompt_tmpl.replace('{{knowledge}}', '\\n\\n'.join([doc.page_content for doc in chunks])).replace('{{query}}', query)\n",
    "    retry_count = 3\n",
    "\n",
    "    resp = ''\n",
    "    while retry_count > 0:\n",
    "        try:\n",
    "            resp = llm.invoke(prompt)\n",
    "            break\n",
    "        except Exception as e:\n",
    "            retry_count -= 1\n",
    "            sleeping_seconds = 2 ** (4 - retry_count)\n",
    "            print(f\"query={query}, error={e}, sleeping={sleeping_seconds}, remaining retry count={retry_count}\")\n",
    "            \n",
    "            time.sleep(sleeping_seconds)\n",
    "    \n",
    "    return resp, chunks"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "166392d8-f801-4372-b8ad-3e79aef0b350",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:40:51.653791Z",
     "iopub.status.busy": "2025-02-27T14:40:51.653623Z",
     "iopub.status.idle": "2025-02-27T14:40:51.665699Z",
     "shell.execute_reply": "2025-02-27T14:40:51.665373Z",
     "shell.execute_reply.started": "2025-02-27T14:40:51.653778Z"
    },
    "papermill": {
     "duration": 0.141864,
     "end_time": "2024-11-23T14:35:27.564409",
     "exception": false,
     "start_time": "2024-11-23T14:35:27.422545",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "prediction_df = qa_df[qa_df['dataset'] == 'test'][['uuid', 'question', 'qa_type', 'answer']].rename(columns={'answer': 'ref_answer'})\n",
    "\n",
    "def predict(vector_db, llm, prediction_df, n_chunks):\n",
    "    prediction_df = prediction_df.copy()\n",
    "    answer_dict = {}\n",
    "\n",
    "    for idx, row in tqdm(prediction_df.iterrows(), total=len(prediction_df)):\n",
    "        uuid = row['uuid']\n",
    "        question = row['question']\n",
    "        answer, chunks = rag(vector_db, llm, question, n_chunks=n_chunks)\n",
    "        assert len(chunks) <= n_chunks\n",
    "        answer_dict[question] = {\n",
    "            'uuid': uuid,\n",
    "            'ref_answer': row['ref_answer'],\n",
    "            'gen_answer': answer,\n",
    "            'chunks': chunks\n",
    "        }\n",
    "\n",
    "    prediction_df.loc[:, 'gen_answer'] = prediction_df['question'].apply(lambda q: answer_dict[q]['gen_answer'])\n",
    "    prediction_df.loc[:, 'chunks'] = prediction_df['question'].apply(lambda q: answer_dict[q]['chunks'])\n",
    "\n",
    "    return prediction_df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "13ed3ce6-460d-496e-8bca-1f733f57cfde",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:40:52.047345Z",
     "iopub.status.busy": "2025-02-27T14:40:52.047139Z",
     "iopub.status.idle": "2025-02-27T14:40:52.049906Z",
     "shell.execute_reply": "2025-02-27T14:40:52.049568Z",
     "shell.execute_reply.started": "2025-02-27T14:40:52.047332Z"
    }
   },
   "outputs": [],
   "source": [
    "save_path = os.path.join(expr_dir, 'pred_df.pkl')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "5b3dff59-03e8-4343-b12f-66c16b4bfa33",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:40:52.313883Z",
     "iopub.status.busy": "2025-02-27T14:40:52.313322Z",
     "iopub.status.idle": "2025-02-27T14:45:14.857787Z",
     "shell.execute_reply": "2025-02-27T14:45:14.855386Z",
     "shell.execute_reply.started": "2025-02-27T14:40:52.313834Z"
    }
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "37146ef5b13c45f3a0edb27b4f7cecc5",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/100 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from tqdm.auto import tqdm\n",
    "\n",
    "pred_df = predict(vector_db, ollama_llm, prediction_df, n_chunks=3)\n",
    "pickle.dump(pred_df, open(save_path, 'wb'))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7d79e974-089f-4c08-ba5e-804f6542e06a",
   "metadata": {
    "papermill": {
     "duration": 0.14423,
     "end_time": "2024-11-23T14:44:03.513124",
     "exception": false,
     "start_time": "2024-11-23T14:44:03.368894",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "# 评估"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "217568fe-c0e4-49eb-9a7c-9fdfbc033d8a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:45:19.212309Z",
     "iopub.status.busy": "2025-02-27T14:45:19.211523Z",
     "iopub.status.idle": "2025-02-27T14:45:19.465507Z",
     "shell.execute_reply": "2025-02-27T14:45:19.464993Z",
     "shell.execute_reply.started": "2025-02-27T14:45:19.212238Z"
    },
    "papermill": {
     "duration": 0.369729,
     "end_time": "2024-11-23T14:44:04.017198",
     "exception": false,
     "start_time": "2024-11-23T14:44:03.647469",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from langchain_openai import ChatOpenAI\n",
    "import time\n",
    "\n",
    "judge_llm = ChatOpenAI(\n",
    "    api_key=os.environ['LLM_API_KEY'],\n",
    "    base_url=os.environ['LLM_BASE_URL'],\n",
    "    model_name='qwen2-72b-instruct',\n",
    "    temperature=0\n",
    ")\n",
    "\n",
    "def evaluate(prediction_df):\n",
    "    \"\"\"\n",
    "    对预测结果进行打分\n",
    "    :param prediction_df: 预测结果，需要包含问题，参考答案，生成的答案，列名分别为question, ref_answer, gen_answer\n",
    "    :return 打分模型原始返回结果\n",
    "    \"\"\"\n",
    "    prompt_tmpl = \"\"\"\n",
    "你是一个经济学博士，现在我有一系列问题，有一个助手已经对这些问题进行了回答，你需要参照参考答案，评价这个助手的回答是否正确，仅回复“是”或“否”即可，不要带其他描述性内容或无关信息。\n",
    "问题：\n",
    "<question>\n",
    "{{question}}\n",
    "</question>\n",
    "\n",
    "参考答案：\n",
    "<ref_answer>\n",
    "{{ref_answer}}\n",
    "</ref_answer>\n",
    "\n",
    "助手回答：\n",
    "<gen_answer>\n",
    "{{gen_answer}}\n",
    "</gen_answer>\n",
    "请评价：\n",
    "    \"\"\"\n",
    "    results = []\n",
    "\n",
    "    for _, row in tqdm(prediction_df.iterrows(), total=len(prediction_df)):\n",
    "        question = row['question']\n",
    "        ref_answer = row['ref_answer']\n",
    "        gen_answer = row['gen_answer']\n",
    "\n",
    "        prompt = prompt_tmpl.replace('{{question}}', question).replace('{{ref_answer}}', str(ref_answer)).replace('{{gen_answer}}', gen_answer).strip()\n",
    "        \n",
    "        retry_count = 3\n",
    "        result = ''\n",
    "        \n",
    "        while retry_count > 0:\n",
    "            try:\n",
    "                result = judge_llm.invoke(prompt).content\n",
    "                break\n",
    "            except Exception as e:\n",
    "                retry_count -= 1\n",
    "                sleeping_seconds = 2 ** (4 - retry_count)\n",
    "                print(f\"query={question}, error={e}, sleeping={sleeping_seconds}, remaining retry count={retry_count}\")\n",
    "                \n",
    "                time.sleep(sleeping_seconds)\n",
    "        \n",
    "        results.append(result)\n",
    "\n",
    "        time.sleep(1)\n",
    "    return results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "fa6420f8-2d67-43bd-8ec6-2f136701e943",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:45:20.149476Z",
     "iopub.status.busy": "2025-02-27T14:45:20.148682Z",
     "iopub.status.idle": "2025-02-27T14:45:20.158652Z",
     "shell.execute_reply": "2025-02-27T14:45:20.156461Z",
     "shell.execute_reply.started": "2025-02-27T14:45:20.149406Z"
    }
   },
   "outputs": [],
   "source": [
    "eval_save_path = os.path.join(expr_dir, 'eval.pkl')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "d1e2d6c9-c45f-442b-8181-66c30437a308",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:45:22.445854Z",
     "iopub.status.busy": "2025-02-27T14:45:22.445483Z",
     "iopub.status.idle": "2025-02-27T14:47:54.505745Z",
     "shell.execute_reply": "2025-02-27T14:47:54.503324Z",
     "shell.execute_reply.started": "2025-02-27T14:45:22.445821Z"
    }
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "079bebe0c4ae414d8bbc2d025ad53d61",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "  0%|          | 0/100 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "pred_df['raw_score'] = evaluate(pred_df)\n",
    "pred_df['score'] = (pred_df['raw_score'] == '是').astype(int)\n",
    "pickle.dump(pred_df, open(eval_save_path, 'wb'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "id": "9fc0c11c-be15-47dc-88bf-31b0192b4622",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:47:54.510310Z",
     "iopub.status.busy": "2025-02-27T14:47:54.509389Z",
     "iopub.status.idle": "2025-02-27T14:47:54.525093Z",
     "shell.execute_reply": "2025-02-27T14:47:54.522759Z",
     "shell.execute_reply.started": "2025-02-27T14:47:54.510237Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.36"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pred_df['score'].mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7bb5ae82-df27-4efc-bcbf-8d67b2f67bbb",
   "metadata": {},
   "source": [
    "# 结果分析"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0c862885-9a39-4bff-ae9e-fa45ede5060e",
   "metadata": {},
   "source": [
    "## 首先检查一下预测结果"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "21302c46-b284-489c-a7c2-0b2b4254ad7e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:52:37.416782Z",
     "iopub.status.busy": "2025-02-27T14:52:37.416572Z",
     "iopub.status.idle": "2025-02-27T14:52:37.420095Z",
     "shell.execute_reply": "2025-02-27T14:52:37.419430Z",
     "shell.execute_reply.started": "2025-02-27T14:52:37.416765Z"
    }
   },
   "source": [
    "可以看出，大部分问题似乎都检索到了相同的知识片段"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "id": "d98a4617-0aae-47f9-a953-0676b1081e34",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:49:04.055864Z",
     "iopub.status.busy": "2025-02-27T14:49:04.055435Z",
     "iopub.status.idle": "2025-02-27T14:49:04.070919Z",
     "shell.execute_reply": "2025-02-27T14:49:04.070587Z",
     "shell.execute_reply.started": "2025-02-27T14:49:04.055828Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>uuid</th>\n",
       "      <th>question</th>\n",
       "      <th>qa_type</th>\n",
       "      <th>ref_answer</th>\n",
       "      <th>gen_answer</th>\n",
       "      <th>chunks</th>\n",
       "      <th>raw_score</th>\n",
       "      <th>score</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>e73a0c9d-d42b-4350-a4c3-b38bf67c68a5</td>\n",
       "      <td>报告的发布机构是什么？</td>\n",
       "      <td>detailed</td>\n",
       "      <td>中国银行研究院</td>\n",
       "      <td>报告的发布机构是中国银行研究院。</td>\n",
       "      <td>[page_content='本研究报告内容及观点仅供参考,不构成任何投资建议。对于本报告所...</td>\n",
       "      <td>是</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>e73a0c9d-d42b-4350-a4c3-b38bf67c68a5</td>\n",
       "      <td>报告的发布日期是什么时候？</td>\n",
       "      <td>detailed</td>\n",
       "      <td>2023年12月12日</td>\n",
       "      <td>报告的发布日期是2023年12月12日。</td>\n",
       "      <td>[page_content='# 全球经济金融展望报告 2024年年报(总第57期) 报告日...</td>\n",
       "      <td>是</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>e73a0c9d-d42b-4350-a4c3-b38bf67c68a5</td>\n",
       "      <td>2023年全球经济增长有什么特点？</td>\n",
       "      <td>detailed</td>\n",
       "      <td>全球经济增长动力持续回落，各国复苏分化，发达经济体增速放缓，新兴经济体表现稳定。</td>\n",
       "      <td>2023年全球经济增长动力持续回落，各国复苏存在较大差异。发达经济体增速明显放缓，新兴经济体...</td>\n",
       "      <td>[page_content='# 全球经济金融展望报告 2024年年报(总第57期) 报告日...</td>\n",
       "      <td>是</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>e73a0c9d-d42b-4350-a4c3-b38bf67c68a5</td>\n",
       "      <td>全球贸易增长情况如何？</td>\n",
       "      <td>detailed</td>\n",
       "      <td>全球贸易增长乏力。</td>\n",
       "      <td>全球贸易增长乏力，各国生产景气度逐渐回落，内需对经济的拉动作用减弱。</td>\n",
       "      <td>[page_content='# 全球经济金融展望报告 2024年年报(总第57期) 报告日...</td>\n",
       "      <td>是</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>e73a0c9d-d42b-4350-a4c3-b38bf67c68a5</td>\n",
       "      <td>展望2024年，全球经济复苏的预期如何？</td>\n",
       "      <td>detailed</td>\n",
       "      <td>全球经济复苏预计将依旧疲软。</td>\n",
       "      <td>预计2024年全球经济复苏将依旧疲软，主要经济体增长态势和货币政策将进一步分化。欧美央行大概...</td>\n",
       "      <td>[page_content='# 全球经济金融展望报告 2024年年报(总第57期) 报告日...</td>\n",
       "      <td>是</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>...</th>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "      <td>...</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>356</th>\n",
       "      <td>584ef542-c5b3-4336-8eae-c30d6f600b5f</td>\n",
       "      <td>2023年全球发展中国家在哪些重要的国际会议上展露出活跃的表现？</td>\n",
       "      <td>large_context</td>\n",
       "      <td>2023年，全球发展中国家在国际政经舞台上表现突出，参与的重要会议包括上海合作组织成员国元首...</td>\n",
       "      <td>根据提供的信息片段，没有直接提到2023年全球发展中国家在特定国际会议上的表现。信息主要关注...</td>\n",
       "      <td>[page_content='# 全球经济金融展望报告 2024年年报(总第57期) 报告日...</td>\n",
       "      <td>否</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>360</th>\n",
       "      <td>d4683862-fed6-4867-a255-29db66011c2a</td>\n",
       "      <td>2024年美联储的货币政策预期如何？</td>\n",
       "      <td>large_context</td>\n",
       "      <td>2024年美联储预计将暂停加息，但是利率水平将较长时间维持在高位，预计会维持每月950亿美元...</td>\n",
       "      <td>2024年，预计美联储将结束本轮紧缩货币周期，其货币政策路线尚不清晰。市场共识认为，当前的货...</td>\n",
       "      <td>[page_content='# 全球经济金融展望报告 2024年年报(总第57期) 报告日...</td>\n",
       "      <td>否</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>365</th>\n",
       "      <td>2accb7dd-1bd7-42c9-89ad-a32b6725c95a</td>\n",
       "      <td>2024年全球资金状况和货币市场基金的前景如何？</td>\n",
       "      <td>large_context</td>\n",
       "      <td>2024年，主要经济体将结束加息周期，资金流动性会呈现“紧平衡”状态，可能导致货币市场脆弱性...</td>\n",
       "      <td>2024年，预计全球经济复苏将保持疲软态势，主要经济体的增长和货币政策将进一步分化。在这一背...</td>\n",
       "      <td>[page_content='# 全球经济金融展望报告 2024年年报(总第57期) 报告日...</td>\n",
       "      <td>否</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>377</th>\n",
       "      <td>61c25726-912a-4bd4-981c-01e9cfa81951</td>\n",
       "      <td>面对经济增长放缓和全球经济挑战，海湾国家采取了什么措施？</td>\n",
       "      <td>large_context</td>\n",
       "      <td>为了应对经济增长放缓和全球经济挑战，沙特、阿联酋等国政府大力推动绿色经济转型和经济多元化改革...</td>\n",
       "      <td>报告中未直接提及海湾六国针对经济增长放缓和全球经济挑战的具体应对措施。不过，考虑到海湾国家通...</td>\n",
       "      <td>[page_content='# 全球经济金融展望报告 2024年年报(总第57期) 报告日...</td>\n",
       "      <td>否</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>385</th>\n",
       "      <td>ddfb44a5-ffa5-4973-a79b-662a0bfeb491</td>\n",
       "      <td>浮动利率房贷在新增房贷中的占比有何变化，为什么会有这种变化？</td>\n",
       "      <td>large_context</td>\n",
       "      <td>浮动利率房贷在新增房贷中的占比上升，这是因为它们通常比固定利率低100个基点以上，这能帮助债...</td>\n",
       "      <td>报告中未直接提及浮动利率房贷在新增房贷中的具体占比变化。但根据内容可以推测，在美联储激进加息...</td>\n",
       "      <td>[page_content='本研究报告内容及观点仅供参考,不构成任何投资建议。对于本报告所...</td>\n",
       "      <td>否</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>100 rows × 8 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "                                     uuid                          question  \\\n",
       "0    e73a0c9d-d42b-4350-a4c3-b38bf67c68a5                       报告的发布机构是什么？   \n",
       "1    e73a0c9d-d42b-4350-a4c3-b38bf67c68a5                     报告的发布日期是什么时候？   \n",
       "2    e73a0c9d-d42b-4350-a4c3-b38bf67c68a5                 2023年全球经济增长有什么特点？   \n",
       "3    e73a0c9d-d42b-4350-a4c3-b38bf67c68a5                       全球贸易增长情况如何？   \n",
       "5    e73a0c9d-d42b-4350-a4c3-b38bf67c68a5              展望2024年，全球经济复苏的预期如何？   \n",
       "..                                    ...                               ...   \n",
       "356  584ef542-c5b3-4336-8eae-c30d6f600b5f  2023年全球发展中国家在哪些重要的国际会议上展露出活跃的表现？   \n",
       "360  d4683862-fed6-4867-a255-29db66011c2a                2024年美联储的货币政策预期如何？   \n",
       "365  2accb7dd-1bd7-42c9-89ad-a32b6725c95a          2024年全球资金状况和货币市场基金的前景如何？   \n",
       "377  61c25726-912a-4bd4-981c-01e9cfa81951      面对经济增长放缓和全球经济挑战，海湾国家采取了什么措施？   \n",
       "385  ddfb44a5-ffa5-4973-a79b-662a0bfeb491    浮动利率房贷在新增房贷中的占比有何变化，为什么会有这种变化？   \n",
       "\n",
       "           qa_type                                         ref_answer  \\\n",
       "0         detailed                                            中国银行研究院   \n",
       "1         detailed                                        2023年12月12日   \n",
       "2         detailed           全球经济增长动力持续回落，各国复苏分化，发达经济体增速放缓，新兴经济体表现稳定。   \n",
       "3         detailed                                          全球贸易增长乏力。   \n",
       "5         detailed                                     全球经济复苏预计将依旧疲软。   \n",
       "..             ...                                                ...   \n",
       "356  large_context  2023年，全球发展中国家在国际政经舞台上表现突出，参与的重要会议包括上海合作组织成员国元首...   \n",
       "360  large_context  2024年美联储预计将暂停加息，但是利率水平将较长时间维持在高位，预计会维持每月950亿美元...   \n",
       "365  large_context  2024年，主要经济体将结束加息周期，资金流动性会呈现“紧平衡”状态，可能导致货币市场脆弱性...   \n",
       "377  large_context  为了应对经济增长放缓和全球经济挑战，沙特、阿联酋等国政府大力推动绿色经济转型和经济多元化改革...   \n",
       "385  large_context  浮动利率房贷在新增房贷中的占比上升，这是因为它们通常比固定利率低100个基点以上，这能帮助债...   \n",
       "\n",
       "                                            gen_answer  \\\n",
       "0                                     报告的发布机构是中国银行研究院。   \n",
       "1                                 报告的发布日期是2023年12月12日。   \n",
       "2    2023年全球经济增长动力持续回落，各国复苏存在较大差异。发达经济体增速明显放缓，新兴经济体...   \n",
       "3                   全球贸易增长乏力，各国生产景气度逐渐回落，内需对经济的拉动作用减弱。   \n",
       "5    预计2024年全球经济复苏将依旧疲软，主要经济体增长态势和货币政策将进一步分化。欧美央行大概...   \n",
       "..                                                 ...   \n",
       "356  根据提供的信息片段，没有直接提到2023年全球发展中国家在特定国际会议上的表现。信息主要关注...   \n",
       "360  2024年，预计美联储将结束本轮紧缩货币周期，其货币政策路线尚不清晰。市场共识认为，当前的货...   \n",
       "365  2024年，预计全球经济复苏将保持疲软态势，主要经济体的增长和货币政策将进一步分化。在这一背...   \n",
       "377  报告中未直接提及海湾六国针对经济增长放缓和全球经济挑战的具体应对措施。不过，考虑到海湾国家通...   \n",
       "385  报告中未直接提及浮动利率房贷在新增房贷中的具体占比变化。但根据内容可以推测，在美联储激进加息...   \n",
       "\n",
       "                                                chunks raw_score  score  \n",
       "0    [page_content='本研究报告内容及观点仅供参考,不构成任何投资建议。对于本报告所...         是      1  \n",
       "1    [page_content='# 全球经济金融展望报告 2024年年报(总第57期) 报告日...         是      1  \n",
       "2    [page_content='# 全球经济金融展望报告 2024年年报(总第57期) 报告日...         是      1  \n",
       "3    [page_content='# 全球经济金融展望报告 2024年年报(总第57期) 报告日...         是      1  \n",
       "5    [page_content='# 全球经济金融展望报告 2024年年报(总第57期) 报告日...         是      1  \n",
       "..                                                 ...       ...    ...  \n",
       "356  [page_content='# 全球经济金融展望报告 2024年年报(总第57期) 报告日...         否      0  \n",
       "360  [page_content='# 全球经济金融展望报告 2024年年报(总第57期) 报告日...         否      0  \n",
       "365  [page_content='# 全球经济金融展望报告 2024年年报(总第57期) 报告日...         否      0  \n",
       "377  [page_content='# 全球经济金融展望报告 2024年年报(总第57期) 报告日...         否      0  \n",
       "385  [page_content='本研究报告内容及观点仅供参考,不构成任何投资建议。对于本报告所...         否      0  \n",
       "\n",
       "[100 rows x 8 columns]"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pred_df"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3c71308b-a161-4c4c-aaef-9982b1916abe",
   "metadata": {},
   "source": [
    "## 检查以chunk作为Query来检索，看能否召回自己"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "80d8aa3b-c41d-409a-b1c9-d82cb47c37b4",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:50:20.313283Z",
     "iopub.status.busy": "2025-02-27T14:50:20.312704Z",
     "iopub.status.idle": "2025-02-27T14:50:23.049514Z",
     "shell.execute_reply": "2025-02-27T14:50:23.049006Z",
     "shell.execute_reply.started": "2025-02-27T14:50:20.313231Z"
    }
   },
   "outputs": [],
   "source": [
    "embedding_fn = CustomEmbeddingFn()\n",
    "\n",
    "chunk_retrieve_data = []\n",
    "for chunk in chunks:\n",
    "    retrieved_docs = vector_db.similarity_search_with_relevance_scores(chunk, k=1)\n",
    "    chunk_retrieve_data.append({\n",
    "        'orig': chunk,\n",
    "        'retrieved': retrieved_docs[0][0].page_content,\n",
    "        'similarity': retrieved_docs[0][1]\n",
    "    })"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "id": "b4ff2060-88fd-40f7-9818-73d7d42bc87b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:50:23.050345Z",
     "iopub.status.busy": "2025-02-27T14:50:23.050209Z",
     "iopub.status.idle": "2025-02-27T14:50:23.052935Z",
     "shell.execute_reply": "2025-02-27T14:50:23.052618Z",
     "shell.execute_reply.started": "2025-02-27T14:50:23.050332Z"
    }
   },
   "outputs": [],
   "source": [
    "retrieved_dbg_df = pd.DataFrame(chunk_retrieve_data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "277d1ecd-156f-4e3b-bf87-8daa296bb354",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:50:23.053459Z",
     "iopub.status.busy": "2025-02-27T14:50:23.053337Z",
     "iopub.status.idle": "2025-02-27T14:50:23.069768Z",
     "shell.execute_reply": "2025-02-27T14:50:23.069444Z",
     "shell.execute_reply.started": "2025-02-27T14:50:23.053447Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>orig</th>\n",
       "      <th>retrieved</th>\n",
       "      <th>similarity</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td># 全球经济金融展望报告 2024年年报(总第57期) 报告日期:2023年12月12日 #...</td>\n",
       "      <td># 全球经济金融展望报告 2024年年报(总第57期) 报告日期:2023年12月12日 #...</td>\n",
       "      <td>0.960631</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>2023年,全球经济增长动力持续回落。分区域看,各国复苏存在较大差异,发达经济体增速明显放缓...</td>\n",
       "      <td># 全球经济金融展望报告 2024年年报(总第57期) 报告日期:2023年12月12日 #...</td>\n",
       "      <td>0.937026</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>二是各国经济走势将进一步分化。相较于新兴市场和发展中经济体,发达经济体面临更大的经济增长压力...</td>\n",
       "      <td># 全球经济金融展望报告 2024年年报(总第57期) 报告日期:2023年12月12日 #...</td>\n",
       "      <td>0.914196</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>分区域看,全球经济复苏不均衡,各国存在较大差异。发达经济体增速明显放缓,预计2023年增速较...</td>\n",
       "      <td># 全球经济金融展望报告 2024年年报(总第57期) 报告日期:2023年12月12日 #...</td>\n",
       "      <td>0.902108</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>15</th>\n",
       "      <td>2023年,新兴经济体表现整体偏弱。全球贸易增长乏力,亚太新兴经济体出口呈大幅下滑态势,自2...</td>\n",
       "      <td># 全球经济金融展望报告 2024年年报(总第57期) 报告日期:2023年12月12日 #...</td>\n",
       "      <td>0.893071</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>38</th>\n",
       "      <td>第二,金融资产质量开始下降。银行业商业房地产贷款拖欠率季度平均值从2022年三季度的 $0....</td>\n",
       "      <td>第二,金融资产质量开始下降。银行业商业房地产贷款拖欠率季度平均值从2022年三季度的 $0....</td>\n",
       "      <td>0.888912</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>18</th>\n",
       "      <td># 二、国际金融回顾与展望 2023年以来,跨境资本回流美国速度放缓,美元指数从高位回落,国...</td>\n",
       "      <td># 二、国际金融回顾与展望 2023年以来,跨境资本回流美国速度放缓,美元指数从高位回落,国...</td>\n",
       "      <td>0.882260</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>37</th>\n",
       "      <td>过去两年,美国居住房地产价格经历了两位数增长。美联储可能在2024年开始降息,房贷利率随之下...</td>\n",
       "      <td>过去两年,美国居住房地产价格经历了两位数增长。美联储可能在2024年开始降息,房贷利率随之下...</td>\n",
       "      <td>0.879990</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>21</th>\n",
       "      <td>2023年,主要经济体货币市场利率与本地区政策利率走势基本保持同步。截至2023年11月15...</td>\n",
       "      <td>2024年,跨境资本流动可能将发生趋势性变化,跨境资本回流美国态势会进一步放缓。惠誉、穆迪下...</td>\n",
       "      <td>0.879512</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>对于私人消费来说,高利率对消费的负面影响将逐渐显现。2023年利率上升增加了美国家庭债务负担...</td>\n",
       "      <td>2023年四季度美国经济增长动力明显回落,更多领域的负面因素开始凸显,不同部门表现分化。一是...</td>\n",
       "      <td>0.876309</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                                 orig  \\\n",
       "0   # 全球经济金融展望报告 2024年年报(总第57期) 报告日期:2023年12月12日 #...   \n",
       "1   2023年,全球经济增长动力持续回落。分区域看,各国复苏存在较大差异,发达经济体增速明显放缓...   \n",
       "6   二是各国经济走势将进一步分化。相较于新兴市场和发展中经济体,发达经济体面临更大的经济增长压力...   \n",
       "2   分区域看,全球经济复苏不均衡,各国存在较大差异。发达经济体增速明显放缓,预计2023年增速较...   \n",
       "15  2023年,新兴经济体表现整体偏弱。全球贸易增长乏力,亚太新兴经济体出口呈大幅下滑态势,自2...   \n",
       "38  第二,金融资产质量开始下降。银行业商业房地产贷款拖欠率季度平均值从2022年三季度的 $0....   \n",
       "18  # 二、国际金融回顾与展望 2023年以来,跨境资本回流美国速度放缓,美元指数从高位回落,国...   \n",
       "37  过去两年,美国居住房地产价格经历了两位数增长。美联储可能在2024年开始降息,房贷利率随之下...   \n",
       "21  2023年,主要经济体货币市场利率与本地区政策利率走势基本保持同步。截至2023年11月15...   \n",
       "9   对于私人消费来说,高利率对消费的负面影响将逐渐显现。2023年利率上升增加了美国家庭债务负担...   \n",
       "\n",
       "                                            retrieved  similarity  \n",
       "0   # 全球经济金融展望报告 2024年年报(总第57期) 报告日期:2023年12月12日 #...    0.960631  \n",
       "1   # 全球经济金融展望报告 2024年年报(总第57期) 报告日期:2023年12月12日 #...    0.937026  \n",
       "6   # 全球经济金融展望报告 2024年年报(总第57期) 报告日期:2023年12月12日 #...    0.914196  \n",
       "2   # 全球经济金融展望报告 2024年年报(总第57期) 报告日期:2023年12月12日 #...    0.902108  \n",
       "15  # 全球经济金融展望报告 2024年年报(总第57期) 报告日期:2023年12月12日 #...    0.893071  \n",
       "38  第二,金融资产质量开始下降。银行业商业房地产贷款拖欠率季度平均值从2022年三季度的 $0....    0.888912  \n",
       "18  # 二、国际金融回顾与展望 2023年以来,跨境资本回流美国速度放缓,美元指数从高位回落,国...    0.882260  \n",
       "37  过去两年,美国居住房地产价格经历了两位数增长。美联储可能在2024年开始降息,房贷利率随之下...    0.879990  \n",
       "21  2024年,跨境资本流动可能将发生趋势性变化,跨境资本回流美国态势会进一步放缓。惠誉、穆迪下...    0.879512  \n",
       "9   2023年四季度美国经济增长动力明显回落,更多领域的负面因素开始凸显,不同部门表现分化。一是...    0.876309  "
      ]
     },
     "execution_count": 48,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "retrieved_dbg_df.sort_values('similarity', ascending=False).head(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "f3b09758-9abd-4016-8de0-4a152cc97c4e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:50:57.309033Z",
     "iopub.status.busy": "2025-02-27T14:50:57.308823Z",
     "iopub.status.idle": "2025-02-27T14:50:57.312141Z",
     "shell.execute_reply": "2025-02-27T14:50:57.311779Z",
     "shell.execute_reply.started": "2025-02-27T14:50:57.309020Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.8548113634612008"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "retrieved_dbg_df['similarity'].mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6acb63e6-ba8d-4a96-9a6e-90365635137c",
   "metadata": {},
   "source": [
    "平均而言，每个chunk自己和自己的相似度只有0.854，这个指标就很低了。为什么自己和自己的相似度不是1，因为作为Query的chunk，是不考虑上下文做的Embedding，而作为知识库片段的chunk，是使用Late Chunking聚合整篇文档信息的Embedding。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "id": "54c14163-035e-46ee-9f52-6461695718df",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:51:06.965026Z",
     "iopub.status.busy": "2025-02-27T14:51:06.964247Z",
     "iopub.status.idle": "2025-02-27T14:51:06.976415Z",
     "shell.execute_reply": "2025-02-27T14:51:06.975946Z",
     "shell.execute_reply.started": "2025-02-27T14:51:06.964956Z"
    }
   },
   "outputs": [],
   "source": [
    "unique_retrieve_docs = retrieved_dbg_df['retrieved'].unique().tolist()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "738abc0c-a6f7-4980-8fb6-53757a84b313",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:51:07.259735Z",
     "iopub.status.busy": "2025-02-27T14:51:07.258967Z",
     "iopub.status.idle": "2025-02-27T14:51:07.270981Z",
     "shell.execute_reply": "2025-02-27T14:51:07.269825Z",
     "shell.execute_reply.started": "2025-02-27T14:51:07.259666Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "20"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(unique_retrieve_docs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "9a099ca8-c7f5-418f-a590-0291a617438f",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:51:15.107257Z",
     "iopub.status.busy": "2025-02-27T14:51:15.107083Z",
     "iopub.status.idle": "2025-02-27T14:51:15.110276Z",
     "shell.execute_reply": "2025-02-27T14:51:15.109820Z",
     "shell.execute_reply.started": "2025-02-27T14:51:15.107243Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "40"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(chunks)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1057776e-e6a6-4ee2-a871-a745472e78f5",
   "metadata": {},
   "source": [
    "共计有40个知识库片段，但是以自己作为Query来进行检索，能检索会来的所有最相似片段只有20个，说明大量chunk作为Query时，连它自己都无法召回"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a2785915-655b-4a76-8fcb-6c2a90f07b74",
   "metadata": {},
   "source": [
    "## 检查chunks之间的两两相似度"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "id": "3c74a606-2138-45db-a1ea-c916795aa5da",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:56:23.278072Z",
     "iopub.status.busy": "2025-02-27T14:56:23.277240Z",
     "iopub.status.idle": "2025-02-27T14:56:25.570729Z",
     "shell.execute_reply": "2025-02-27T14:56:25.570235Z",
     "shell.execute_reply.started": "2025-02-27T14:56:23.278000Z"
    }
   },
   "outputs": [],
   "source": [
    "chunk_in_query_embeddings = np.array([vector_db.embeddings.embed_query(chunk) for chunk in chunks])\n",
    "chunk_in_late_embeddings = np.array(late_embeddings[0])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "90269fbe-d26a-4f61-81b4-3ed1c8e7494e",
   "metadata": {},
   "source": [
    "chunk_in_query_embeddings是把每个知识库片段作为Query时的Embedding，chunk_in_late_embeddings是每个片段作为知识库片段时，使用late chunking获得的Embedding"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "id": "d7d7ea19-af9f-42f1-9b4f-e1a2c871227b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:56:26.122676Z",
     "iopub.status.busy": "2025-02-27T14:56:26.121860Z",
     "iopub.status.idle": "2025-02-27T14:56:26.135834Z",
     "shell.execute_reply": "2025-02-27T14:56:26.133481Z",
     "shell.execute_reply.started": "2025-02-27T14:56:26.122606Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "((40, 1024), (40, 1024))"
      ]
     },
     "execution_count": 62,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chunk_in_query_embeddings.shape, chunk_in_late_embeddings.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "id": "f5a9beae-0287-4085-942a-2c8d4d900ca7",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:57:11.977148Z",
     "iopub.status.busy": "2025-02-27T14:57:11.976927Z",
     "iopub.status.idle": "2025-02-27T14:57:11.986116Z",
     "shell.execute_reply": "2025-02-27T14:57:11.985730Z",
     "shell.execute_reply.started": "2025-02-27T14:57:11.977129Z"
    }
   },
   "outputs": [],
   "source": [
    "from sklearn.metrics.pairwise import cosine_similarity\n",
    "\n",
    "cos_sim = cosine_similarity(chunk_in_query_embeddings, chunk_in_late_embeddings)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "id": "60c1dbd8-fcea-4696-a68b-30d9044fae2f",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:58:05.062447Z",
     "iopub.status.busy": "2025-02-27T14:58:05.061930Z",
     "iopub.status.idle": "2025-02-27T14:58:05.329360Z",
     "shell.execute_reply": "2025-02-27T14:58:05.328925Z",
     "shell.execute_reply.started": "2025-02-27T14:58:05.062403Z"
    }
   },
   "outputs": [],
   "source": [
    "import seaborn as sns\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "id": "a5c49074-3271-4103-bbf7-80eaf9fa0676",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-27T14:58:05.801409Z",
     "iopub.status.busy": "2025-02-27T14:58:05.799811Z",
     "iopub.status.idle": "2025-02-27T14:58:06.110584Z",
     "shell.execute_reply": "2025-02-27T14:58:06.110080Z",
     "shell.execute_reply.started": "2025-02-27T14:58:05.801332Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Axes: >"
      ]
     },
     "execution_count": 67,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAoUAAAJ8CAYAAACItNsFAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/TGe4hAAAACXBIWXMAAA9hAAAPYQGoP6dpAACRS0lEQVR4nOzdeXhTZdo/8G+WJt1TurdAKWvZCxapLIMgWCgMgvoKIsqi4vIWFToyUmVTBwvqIIx2ivpjGx0GFCniVkSwIMMmhY6ggOwV6EKBbilN0yS/P3jpEJrS3s0JpfX7ua5zXTS989zPyUnC03PO89wqm81mAxERERH9rqkbugNERERE1PA4KCQiIiIiDgqJiIiIiINCIiIiIgIHhUREREQEDgqJiIiICBwUEhERERE4KCQiIiIicFBIRERERAC0Dd0BIiIiImd95RbVYLlHmI82WG4l8UwhEREREfFMIRERETV+KjdVQ3eh0eOZQiIiIiLioJCIiIiIePmYiIiImgC1lpePncUzhURERETEM4VERETU+KnceJ7LWXwFiYiIiIiDQiIiIiLi5WMiIiJqAjjRxHk8U0hEREREPFNIREREjR8rmjiPZwqJiIiIiGcKiYiIqPHjPYXO45lCIiIiIuKgkIiIiIh4+ZiIiIiaAE40cR7PFBIRERERzxQSERFR48eJJs7jmUIiIiIi4qCQiIiIiHj5mIiIiJoAlYaXj53FM4VERERExDOFRERE1PipeabQaTxTSEREREQ8U0hERESNn0rNM4XO4plCIiIiIuKgkIiIiIh4+ZiIiIiaAJWG57mcxVeQiIiIiDgoJCIiosZPrVE12FYfKSkpiIyMhLu7O2JjY7F3794aY81mM1577TW0bdsW7u7uiI6ORnp6ul3MvHnzoFKp7LaOHTvKXsN67QkRERER1cvatWuRmJiIuXPnYv/+/YiOjsbQoUORn5/vMH7WrFl4//338e677+KXX37BM888g/vvvx8HDhywi+vSpQtycnKqth07doj6xUEhERER0S20aNEiTJkyBZMnT0bnzp2xdOlSeHp6Yvny5Q7jP/roI7z88ssYPnw42rRpg2effRbDhw/HX//6V7s4rVaL0NDQqi0wMFDULw4KiYiIqNFTqVUNtklUVFQgMzMTQ4YMqXpMrVZjyJAh2LVrl8PnmEwmuLu72z3m4eFR7UzgsWPHEB4ejjZt2mD8+PHIzs4W9Y2DQiIiIiInmEwmFBcX220mk8lhbEFBASwWC0JCQuweDwkJQW5ursPnDB06FIsWLcKxY8dgtVqxefNmrF+/Hjk5OVUxsbGxWLlyJdLT05GamopTp07hD3/4A0pKSuq8HxwUEhERUaPXkBNNkpOTYTAY7Lbk5GTF9m3JkiVo3749OnbsCJ1Oh6lTp2Ly5MlQq/87jIuPj8dDDz2E7t27Y+jQofj6669RWFiITz75pO6voWI9JiIiIvodSkpKQlFRkd2WlJTkMDYwMBAajQZ5eXl2j+fl5SE0NNThc4KCgrBhwwYYjUacOXMGR44cgbe3N9q0aVNjn/z8/NChQwccP368zvvBQSERERGRE/R6PXx9fe02vV7vMFan0yEmJgZbtmypesxqtWLLli3o06fPTfO4u7ujefPmqKysxGeffYZRo0bVGFtaWooTJ04gLCyszvvBiiZERETU6KnquV5gQ0hMTMTEiRPRq1cv9O7dG4sXL4bRaMTkyZMBABMmTEDz5s2rLkHv2bMH586dQ48ePXDu3DnMmzcPVqsVf/7zn6vafPHFFzFy5Ei0atUK58+fx9y5c6HRaDBu3Lg694uDQiIiIqJbaOzYsbhw4QLmzJmD3Nxc9OjRA+np6VWTT7Kzs+3uFywvL8esWbNw8uRJeHt7Y/jw4fjoo4/g5+dXFXP27FmMGzcOFy9eRFBQEPr374/du3cjKCiozv1S2Ww2m2J7SURERNQAMgf1a7DcMd//u8FyK4n3FBIRERERLx8TERFR4yddRJqq45lCIiIiIuKgkIiIiIh4+ZiIiIiaAHUjWpLmdsUzhURERETEM4VERETU+HGiifN4ppCIiIiIOCgkIiIiIl4+JiIioiZApeZ5LmfxFSQiIiIinikkIiKixo8TTZzHM4VERERExDOFRERE1Phx8Wrn8UwhEREREXFQSERERES8fExERERNACeaOI9nComIiIjIdWcKU1JS8NZbbyE3NxfR0dF499130bt37zo99yu3KHG+kL7+oviuz48R5yjodq8oPvBwhijeWpAvigeAioJLonj3O3qJc1T++osoXhvWXBRvDQoXxQPAxdAuovhmF4+Lc1wKaC/LcfmkKL7Ir5UoHgDyESaK16srxDna/meNKN7mHyyKV1WaRfEAUBEge09pTEZxDnW57DlWvYesfdMVUTwA5ETcJYoPP/mDOIcpoIUo/opngCjerVK+39qKMlF8pc5TnOOUWydR/L7TzUTxf2x9SBQPAOetLUXxIdpccQ6tVfadUKbxFcW3byv/XlMKF692nktewbVr1yIxMRFz587F/v37ER0djaFDhyI/Xz7oISIiIiLXc8mgcNGiRZgyZQomT56Mzp07Y+nSpfD09MTy5ctdkY6IiIiInKT4oLCiogKZmZkYMmTIf5Oo1RgyZAh27dqldDoiIiIiqNSqBtuaCsUHhQUFBbBYLAgJCbF7PCQkBLm58vsfiIiIiMj1GnxJGpPJBJPJZPeY2WaFm4o3jBIREVHdNKUzdg1F8ZFXYGAgNBoN8vLy7B7Py8tDaGhotfjk5GQYDAa77ROrbEYtERERETlH8UGhTqdDTEwMtmzZUvWY1WrFli1b0KdPn2rxSUlJKCoqstvGqGXLyxAREdHvG+8pdJ5LLh8nJiZi4sSJ6NWrF3r37o3FixfDaDRi8uTJ1WL1ej30er3dY7x0TERERHRruWRQOHbsWFy4cAFz5sxBbm4uevTogfT09GqTT4iIiIjo9uCyiSZTp07F1KlTXdU8ERERURVWNHEeX0EiIiIiavglaRzx6+otfk5A2yBRvDVQVkMWAApUssvf/sIcao1GFA8A2vJyUbzV3Uuew19W69QaIqulWtpMXiszzyp7bbV+8hrA0hxuvqbag64jrWMMAHlGWR1SN41VnKNV87ai+DJfWe1q9/LLongAuOQre494mEvEObQW2fEza2W1j7WVss8qAORWyOpK+4XIjh0AXPSKEMVfscr2W+8me10BwN1dVvu4QuUuzpF90SCKP35S1qfSdn6ieAAouiLbD4ObvOazVSP7//WSSfY6ySrGK0utaToTPhqK4mcKt2/fjpEjRyI8PBwqlQobNmxQOgURERERKUzxQaHRaER0dDRSUlKUbpqIiIiIXETxy8fx8fGIj49XulkiIiKiGjWl9QIbCieaEBEREdHtOdGEiIiISIJL0jivwQeFJpMJJpP97LQKqxU6HlwiIiKiW6bBR17JyckwGAx220d5uQ3dLSIiImpEWPvYeQ0+KExKSkJRUZHd9lhIaEN3i4iIiOh3RfHLx6WlpTh+/HjVz6dOnUJWVhb8/f0REVF9kVS9Xg+9Xm/3GC8dExEREd1aig8K9+3bh0GDBlX9nJiYCACYOHEiVq5cqXQ6IiIioiZ1GbehKD4oHDhwIGw2m9LNEhEREZELNfjsYyIiIiJncUka5yk+KExOTsb69etx5MgReHh4oG/fvli4cCGioqLq3EZgh0BxXulp49Jv08U5OvY4J4ovO/qrKN7N4CuKB4DyvAJRvI//SXGOyksXRfFaTy9RvG9BjigeADqGyp6jPfmLOIdfaAtRvKqsRBTvHXxeFA8A3v5dRfEe1lJxDu3p30TxvsZCUbypWbgoHgA8K4pF8Ra1/KtNZbWI4t3Li0Tx2nLZPgBAWFCeKF5dbhbn8KqU7YeHSvY+15nKRfEA4Htqn+wJ7p7iHJbIe0TxFdHNRfFuqgpRPAB460y1B13HBvnlUndcEebwE+egxkvxYfW2bduQkJCA3bt3Y/PmzTCbzYiLi4PRaFQ6FREREREpRPEzhenp9mfgVq5cieDgYGRmZmLAgAFKpyMiIiLiRBMFuPwCfFHR1UsT/v7+rk5FRERERPXk0okmVqsV06ZNQ79+/dC1q+xeKCIiIqK64kQT57l0UJiQkIBDhw5hx44dNcY4rH1ssUKn4cElIiIiulVcNvKaOnUqvvzyS3z//fdo0aLmWZyOah+/f1g+Q5aIiIh+x1SqhtuaCMUHhTabDVOnTkVaWhq2bt2K1q1b3zTeUe3jpzu1UbpbRERERHQTil8+TkhIwOrVq/H555/Dx8cHubm5AACDwQAPD49q8Q5rH/PSMREREdEtpfigMDU1FcDVcnfXW7FiBSZNmqR0OiIiIiIuSaMAxQeFrHtMRERE1Piw9jERERE1elySxnkuuXycmpqK06dPAwC6dOmCOXPmID4+vs5ttHp8jDhvefDNJ7TcqEIvrzN8QNVBFN9cWCu5WNVMFA8AzY1HRfHZ3rLXCQDCLh4UxV/0ixDF68xlongAKHCX1SU2+LUS5/jV3F4UH+Auq217qlBe4/vMEdmXnroel1OGdPERxV+s8BPFB+tk9boBINcULIovM7mJc2jUVlF8UYVOFK/TydoHgJ/2yY5f17byz/dvJzWieOkt317VbyWvVXiEbF1bYz2O97GDsh3J3C37Ptc/UI/vnGzZ8e4VJXsPAoBGJbuaV2GRvT+ocVN8WN2iRQssWLAAmZmZ2LdvH+655x6MGjUKP//8s9KpiIiIiEghip8pHDlypN3P8+fPR2pqKnbv3o0uXboonY6IiIiIE00U4NJ7Ci0WCz799FMYjUb06dPHlamIiIiIyAkuGRQePHgQffr0QXl5Oby9vZGWlobOnTu7IhURERERJ5oowCWDwqioKGRlZaGoqAjr1q3DxIkTsW3bNocDQ0e1j20VZuh18huHiYiIiKh+XDKs1ul0aNeuHWJiYpCcnIzo6GgsWbLEYayj2sdvrf3aFd0iIiKiJkqlVjXY1lTcknOtVqu12tnAaxzVPp4xdvit6BYRERER/R/FLx8nJSUhPj4eERERKCkpwerVq5GRkYFNmzY5jHdU+7icl46JiIiIbinFB4X5+fmYMGECcnJyYDAY0L17d2zatAn33nuv0qmIiIiIAHBJGiUoPihctmyZ0k0SERERkYux9jERERE1flySxml8BYmIiIjI9WcKFyxYgKSkJLzwwgtYvHhxnZ5z+dst4jw6g7csXi8vJN6zq6xIu+nwYVF8UEiQKB4AKguLRPEtu3QX58C5M6LwgOBcWfuVZlk8APeQy6J4t3PHxTliws+K4m0mWeF4r2btRPEA0MbPSxTvoS4T52h+ULYkVIRvM1G8ymoRxQNAiG+gKF5dWSHOoTLLnlPpZRDF63JlnyMAGNC+tSheZZF/li61byuKr1TLJgLqLOWieABodlH2ebW66WsPukH/trLP0j1dOoriO55dI4oHgP6d24vi9eWy738AUJtlx6PE0FKYoYcwnm4nLh0U/vjjj3j//ffRvXs9BiJEREREdaRScaKJs1x2+bi0tBTjx4/Hhx9+iGbNZGcSiIiIiJqylJQUREZGwt3dHbGxsdi7d2+NsWazGa+99hratm0Ld3d3REdHIz093ak2HXHZoDAhIQEjRozAkCFDXJWCiIiICMDV2scNtUmtXbsWiYmJmDt3Lvbv34/o6GgMHToU+fn5DuNnzZqF999/H++++y5++eUXPPPMM7j//vtx4MCBerfpiEsGhWvWrMH+/fuRnJzsiuaJiIiIGq1FixZhypQpmDx5Mjp37oylS5fC09MTy5cvdxj/0Ucf4eWXX8bw4cPRpk0bPPvssxg+fDj++te/1rtNRxS/p/C3337DCy+8gM2bN8Pd3b3WeJPJVK0EnqnSAr1WdtM+ERERUUNwNJZxVLENACoqKpCZmYmkpKSqx9RqNYYMGYJdu3bV2P6NYyoPDw/s2LGj3m06oviZwszMTOTn5+OOO+6AVquFVqvFtm3b8Le//Q1arRYWi/3Mw+TkZBgMBrvt3b2/KN0tIiIiasJUalWDbY7GMjVdLS0oKIDFYkFISIjd4yEhIcjNdbx6x9ChQ7Fo0SIcO3YMVqsVmzdvxvr165GTk1PvNh1RfFA4ePBgHDx4EFlZWVVbr169MH78eGRlZUGjsT8DmJSUhKKiIrvtud6dle4WERERkUs4Gstcf9bOWUuWLEH79u3RsWNH6HQ6TJ06FZMnT4Za4QW7Fb987OPjg643rOfn5eWFgICAao8Djk+vGnnpmIiIiCQasKJJTZeKHQkMDIRGo0FeXp7d43l5eQgNDXX4nKCgIGzYsAHl5eW4ePEiwsPDMXPmTLRp06bebTrCiiZEREREt4hOp0NMTAy2bPlvoQ6r1YotW7agT58+N32uu7s7mjdvjsrKSnz22WcYNWqU021e75bUPs7IyLgVaYiIiOh3SqVuPItXJyYmYuLEiejVqxd69+6NxYsXw2g0YvLkyQCACRMmoHnz5lX3Je7Zswfnzp1Djx49cO7cOcybNw9WqxV//vOf69xmXdySQSERERERXTV27FhcuHABc+bMQW5uLnr06IH09PSqiSLZ2dl29wuWl5dj1qxZOHnyJLy9vTF8+HB89NFH8PPzq3ObdaGy2Ww2xfYSwLx58/Dqq6/aPRYVFYUjR47UuY2it18Q53ULChDFWzv2FOfIDogRxbc5850o3nLyV1E8AKh0shrORbH3iXMY8mX9KvcLE8Xb1PJ7SC96tBDFB5WeEuco8I4UxYde+lkUX+gnax8AjpTJ6tTqtZXiHD2v/CCKv+IprEtsldfnLfYIFsVrbPL91lVeEcVXaD1E8SqbVRQPyI/3XZXfi3OUe8i+Owt04aJ4rUp+LFSQ/bdUYZPXsj9VLKs1f+CorP0RMfK6xGeL/UTxLQ2yGvAA4CY8HgXlshrfA7vKPhdKuvSXpxsst/+s9xsst5JccqawS5cu+O67/w6ItFqekCQiIiLXUak4TcJZLhmtabVa0WwXIiIiImpYLhlWHzt2DOHh4WjTpg3Gjx+P7OxsV6QhIiIiukqtaritiVB8UBgbG4uVK1ciPT0dqampOHXqFP7whz+gpKRE6VREREREpBDFLx/Hx8dX/bt79+6IjY1Fq1at8Mknn+CJJ56oFu+49nEl9LwPkYiIiOiWcfldmX5+fujQoQOOHz/u8PeO6gUu2rrP1d0iIiKiJkSlVjfY1lS4fE9KS0tx4sQJhIU5XqbEUb3AxHt6ubpbRERERHQdxa/Rvvjiixg5ciRatWqF8+fPY+7cudBoNBg3bpzDeEf1Am28dExEREQCjamiye1K8dHX2bNnMW7cOFy8eBFBQUHo378/du/ejaAg2UKhRERERHTrKD4oXLNmjdJNEhEREd0cF692Gl9BIiIiInJNRRNnndn6H/Fz/NvKaqMGeniKcwT51L2oNADg0gVRuMrNTdY+gJJfjonim3luEecoOyqrfezRJlIUb2nbVRQPACqP5qJ4tyvyOqRe7rLnaEsuiuI9PJqJ4gHAR18uindTW8Q53M6ekz3BKsuhKTfK2gdgC3D93686k2wtVb1WX3vQddyE7QNAi2ayurOqS/I6w2bhftggu29LDfl7MLBYVqvcrPMS58h38xPFa9Sy+sqeGlktbQBwd/MRxfurZN85AGBVyWrNn7f4i3NQ4+WSb9pz587h0UcfRUBAADw8PNCtWzfs28dlZoiIiMg1VGpVg21NheJnCi9fvox+/fph0KBB+OabbxAUFIRjx46hWTP5WREiIiIiujUUHxQuXLgQLVu2xIoVK6oea926tdJpiIiIiP6rCS0i3VAUfwU3btyIXr164aGHHkJwcDB69uyJDz/8UOk0RERERKQgxQeFJ0+eRGpqKtq3b49Nmzbh2WefxfPPP49Vq1YpnYqIiIiIFKL45WOr1YpevXrhjTfeAAD07NkThw4dwtKlSzFx4sRq8SaTCSaTye6xCosVOg1PAxMREVHdqFRNZ8JHQ1F85BUWFobOnTvbPdapUydkZ2c7jE9OTobBYLDblp10HEtERERErqH4oLBfv344evSo3WO//vorWrVq5TA+KSkJRUVFdtsTbSKU7hYRERE1ZWp1w21NhOKXj6dPn46+ffvijTfewJgxY7B371588MEH+OCDDxzG6/V66PX2i6fy0jERERHRraX4oPDOO+9EWloakpKS8Nprr6F169ZYvHgxxo8fr3QqIiIiIgBoUotINxSXlLn74x//iD/+8Y+uaJqIiIiIXIDXaYmIiIhI+TOFkZGROHPmTLXH//d//xcpKSl1aiO8V1txXq2XhyjeVmkW53A3FsieYLOJwtXNAmTtA9B6/CaKN50+Lc5hraiUPcFiEYVr8+SzzYPdZMdbWywvHO+p95Y9QSX7G0ttFb6uAGw22eURnVr+Prd6+4nibVqdLIGtRBYPwP3KZVG8yd0gzmETHj+LVl970HU0labag26gVllF8cV+8kl6RWrZ946HqkwUr7NcEcUDgNZUKopXW+Xv8xZ++aL4rm1biOJDi38VxQOA3rdcFO9XJPv+BwCVTfb9nOcVJMwg/D5QkvAzTNUpPij88ccfYbluUHDo0CHce++9eOihh5RORUREREQKUXxQGBRk/1fFggUL0LZtW9x9991KpyIiIiK6ihNNnObSc60VFRX4+OOP8fjjj3OlcSIiIqLbmEsHhRs2bEBhYSEmTZrkyjRERERE5CSXLElzzbJlyxAfH4/w8PAaYxzVPjZVWqDXalzZNSIiImpCVJxo4jSXvYJnzpzBd999hyeffPKmcY5qHy/5939c1S0iIiIicsBlg8IVK1YgODgYI0aMuGmco9rHL/SLdlW3iIiIqClSqxpuayJccvnYarVixYoVmDhxIrTam6dwVPu4gpeOiYiIiG4plwwKv/vuO2RnZ+Pxxx93RfNEREREdlRq3lPoLJcMCuPi4mATVvMgIiIioobDYTURERERKX+m0GKxYN68efj444+Rm5uL8PBwTJo0CbNmzarzAtZqnbxbutBgUXxlh57iHCcMMaL41u1kNSBVkJ9d9TLJamVaWrQR58DObaJwld5dFH+lVVdRPACc8pA9p7lHM3GOc5pIUXyYh78o/rxaXqf2P6d8RfHuelk8ALT0k9XCLfYKEcUbIL8p+5IhUhRvrcfSFG4WWW3iMrWPKN5d5yeKB4DsUtn3WjtveX3logpZje+cStn73F0jr/FdHCjLYbLJ6+2eKJDl2H9IVl+5/cAoUTwAnC0NFMX31F0Q56jUyr6fL1/xFOdoMCyS4TTFB4ULFy5EamoqVq1ahS5dumDfvn2YPHkyDAYDnn/+eaXTEREREZECFB8U7ty5E6NGjapaiiYyMhL/+te/sHfvXqVTEREREV3FiSZOU/wV7Nu3L7Zs2YJff/0VAPCf//wHO3bsQHx8vNKpiIiIiEghip8pnDlzJoqLi9GxY0doNBpYLBbMnz8f48ePVzoVERERESlE8UHhJ598gn/+859YvXo1unTpgqysLEybNg3h4eGYOHFitXjWPiYiIiKncaKJ0xS/fDxjxgzMnDkTDz/8MLp164bHHnsM06dPR3JyssN4R7WPF28/oHS3iIiIiOgmFB8UlpWVQX3DzZ4ajQZWq9VhvKPax9MGyJeLISIiot8vlVrdYFtTofjl45EjR2L+/PmIiIhAly5dcODAASxatKjGkneOah9X8tIxERER0S2l+KDw3XffxezZs/G///u/yM/PR3h4OJ5++mnMmTNH6VREREREV9Vj0Xqyp/ig0MfHB4sXL8bixYuVbpqIiIiIXITDaiIiIiJS/kwhERER0S2n5pI0znLJoLCkpASzZ89GWloa8vPz0bNnTyxZsgR33nlnnZ5vLikT59TkywqD6/2Oi3M092gmy5F/WhRv03uI4gHAcvmyKF7jmSfOUfhbrijeUl4uivfUyYvZt24ti3e/fF6cwxLmJor3KfpNFB/sL9/v4GZ+ongfvVmcw134vtVUGEXxbpdyRPEAEFhpqj3oemr5ZDWVRfZaefiEiOLdS2XfUQDQwV8W71dSj/e5j+y/gUK1QRSvV1eI4gHAz1Igijdr9LUH3aDST7bfJW38RPGtcneL4gEgsFlLUbz3rz+Kc0Ar+15r0ylQmEC2D3R7ccmg8Mknn8ShQ4fw0UcfITw8HB9//DGGDBmCX375Bc2bN3dFSiIiIvodU3GiidMUfwWvXLmCzz77DG+++SYGDBiAdu3aYd68eWjXrh1SU1OVTkdEREREClB8UFhZWQmLxQJ3d3e7xz08PLBjxw6l0xERERGRAhQfFPr4+KBPnz54/fXXcf78eVgsFnz88cfYtWsXcnLk9xIRERER1UqtaritiXDJBfiPPvoINpsNzZs3h16vx9/+9jeMGzeuWvk7ADCZTCguLrbbTJUWV3SLiIiIiGrgkkFh27ZtsW3bNpSWluK3337D3r17YTab0aZNm2qxycnJMBgMdtvfdh9yRbeIiIioqVKpG25rIly6J15eXggLC8Ply5exadMmjBo1qlpMUlISioqK7Lbn7+rqym4RERER0Q1csiTNpk2bYLPZEBUVhePHj2PGjBno2LEjJk+eXC1Wr9dDr7dfY+qKVr7GGBEREf2OqZrOvX0NxSVnCouKipCQkICOHTtiwoQJ6N+/PzZt2gQ3N9mimURERER0a7jkTOGYMWMwZswYVzRNRERERC7A2sdERETU+DlY4YRkxIPC7du346233kJmZiZycnKQlpaG0aNHV/3eZrNh7ty5+PDDD1FYWIh+/fohNTUV7du3r3MOn851j71G7eEpircVF4pzeF3Klj2hUlZLtTxMvt/6zrL6uSX+EeIcAYOtsid4+YjCjf+WL2quO3NGFG8qF9bOBeDfS3b8TM3CRfFlatnrBADuWtlyTR5uleIcFi9fUbxVK6s7W9a8oygeAMr0fuLnSGmtsuNd4iYrTKzTyWoGA0C2SVYW1OQjr59+qULWLxtk922pIL9tqFzrJYqvrEeOIpPstSoqsYniz3S5SxQPABfK/UTxAV3ldYb1Kllt+lKL7FhQ4yYeVhuNRkRHRyMlJcXh799880387W9/w9KlS7Fnzx54eXlh6NChKC+XvRGJiIiI6oxL0jhNfKYwPj4e8fHxDn9ns9mwePFizJo1q2r5mX/84x8ICQnBhg0b8PDDDzvXWyIiIiJyCUWHt6dOnUJubi6GDBlS9ZjBYEBsbCx27dqlZCoiIiIiUpCiE01yc3MBACEhIXaPh4SEVP2OiIiISHFNqAZxQ2nw2ccmkwkmk/0kAIu5Enq3Bu8aERER0e+GopePQ0NDAQB5eXl2j+fl5VX97kaOah+//eUPSnaLiIiImjpONHGaonvSunVrhIaGYsuWLVWPFRcXY8+ePejTp4/D5ziqffziH/+gZLeIiIiIqBbiQWFpaSmysrKQlZUF4OrkkqysLGRnZ0OlUmHatGn4y1/+go0bN+LgwYOYMGECwsPD7dYyvJ5er4evr6/dxkvHRERE1JSlpKQgMjIS7u7uiI2Nxd69e28av3jxYkRFRcHDwwMtW7bE9OnT7Zb7mzdvHlQqld3WsaNsXVjx6Gvfvn0YNGhQ1c+JiYkAgIkTJ2LlypX485//DKPRiKeeegqFhYXo378/0tPT4e7uLk1FREREVDeqxjPRZO3atUhMTMTSpUsRGxuLxYsXY+jQoTh69CiCg4Orxa9evRozZ87E8uXL0bdvX/z666+YNGkSVCoVFi1aVBXXpUsXfPfdd1U/a7WyYZ54UDhw4EDYbDWv7K5SqfDaa6/htddekzZNRERE1OQtWrQIU6ZMweTJkwEAS5cuxVdffYXly5dj5syZ1eJ37tyJfv364ZFHHgEAREZGYty4cdizZ49dnFarrXEOR100nbsjiYiI6PdLrW64TaCiogKZmZl2azqr1WoMGTKkxjWd+/bti8zMzKpLzCdPnsTXX3+N4cOH28UdO3YM4eHhaNOmDcaPH4/sbFl53tvy5j11mLyeo1VYr7Xcp/rp2dqc8+wgig8OPCuKL6tHbVR3vew5v6G1OEen0AJRvE0rq8fsHhIkigcAtaesbml93uhXAluJ4jWWClG8CrJaqgBgqpR9+ZRWyGvCmj38RPHlHs1E8bqKUlE8ANiEs/sqNPLbVWwWWSnOSuG7yqaS1yUuNsnqSrfWlYhzVArv4S4wyb5z6vM+zzcHiuIrLPJPeG6R7HsqN09WP/1KR/l7sLxS9nmt0Mk/39LjYbFqxDl+jxwtr6fX66HXV/8MFxQUwGKxOFzT+ciRIw7bf+SRR1BQUID+/fvDZrOhsrISzzzzDF5++eWqmNjYWKxcuRJRUVHIycnBq6++ij/84Q84dOgQfHx86rQf4jOF27dvx8iRIxEeHg6VSoUNGzbY/X79+vWIi4tDQEAAVCpV1YQUIiIiIpdRqRpsc7S8XnJysmK7lpGRgTfeeAN///vfsX//fqxfvx5fffUVXn/99aqY+Ph4PPTQQ+jevTuGDh2Kr7/+GoWFhfjkk0/qnEf855XRaER0dDQef/xxPPDAAw5/379/f4wZMwZTpkyRNk9ERETUqCQlJVVNvL3G0VlCAAgMDIRGoxGt6Tx79mw89thjePLJJwEA3bp1q5rU+8orr0Dt4BK2n58fOnTogOPHj9d5P8SDwvj4eMTHx9f4+8ceewwAcPr0aWnTRERERI1OTZeKHdHpdIiJicGWLVuqluuzWq3YsmULpk6d6vA5ZWVl1QZ+Gs3VS/s1Tf4tLS3FiRMnqsZldXFb3lNIREREJNKIKoskJiZi4sSJ6NWrF3r37o3FixfDaDRWzUaeMGECmjdvXnUJeuTIkVi0aBF69uyJ2NhYHD9+HLNnz8bIkSOrBocvvvgiRo4ciVatWuH8+fOYO3cuNBoNxo0bV+d+cVBIREREdAuNHTsWFy5cwJw5c5Cbm4sePXogPT29avJJdna23ZnBWbNmQaVSYdasWTh37hyCgoIwcuRIzJ8/vyrm7NmzGDduHC5evIigoCD0798fu3fvRlBQ3SdzNvig0NGMHVuFGfp6zKoiIiKi3ynh0jANberUqTVeLs7IyLD7WavVYu7cuZg7d26N7a1Zs8bpPjX4K+hoxs5ba79q6G4RERER/a40+KAwKSkJRUVFdtuMsSMaultEREREvyviy8elpaV205tPnTqFrKws+Pv7IyIiApcuXUJ2djbOnz8PADh69CgAIDQ01OFUa0czdsp56ZiIiIgkGlHt49uV+Ezhvn370LNnT/Ts2RPA1Rk0PXv2xJw5cwAAGzduRM+ePTFixNWzfQ8//DB69uyJpUuXKthtIiIiIlKS+EzhwIEDa1wTBwAmTZqESZMmOdMnIiIiIplGtCTN7YqvIBERERHJzxRu374db731FjIzM5GTk4O0tLSqFbnNZjNmzZqFr7/+GidPnoTBYMCQIUOwYMEChIeH1zmHNec3abeg9q5bsedrPIsuinOER8gKg3sWnBHF65rV/TWqek7ZZVF88wB5cXO3nFOyJ+hlheArK82y9gGodAZR/OW9WeIcvmVXZE/oFiMKVxsssvYBBHiVi+I9tPV4bY1WUbzaKtsPo0eAKB4AjGpf2RNqvphRI42qUhSvhSzew1IiigeAQE/Z+7xSrRPnuFIp+7zabK6/b6u55pwovkIn2wcAKPNpIYpv1kz22l6plL0/AKCwTPZfsrvWQ5zD5iY7fhq1/HuqwfCeQqeJzxReq32ckpJS7XdlZWXYv38/Zs+eXVWw+ejRo7jvvvsU6SwRERERuYaitY8NBgM2b95s99h7772H3r17Izs7GxEREfXrJRERERG5lMsrmhQVFUGlUsHPz8/VqYiIiOj3qpFVNLkdufQVLC8vx0svvYRx48bB11d4TxARERER3TIuO1NoNpsxZswY2Gw2pKam1hjnqPaxxVwJvVuDl2UmIiKiRsLGiSZOc8mZwmsDwjNnzmDz5s03PUvoqPbx21/+4IpuEREREVENFB8UXhsQHjt2DN999x0CAm6+/ISj2scv/vEPSneLiIiIiG5C0drHYWFh+J//+R/s378fX375JSwWC3JzcwEA/v7+0Omqr/PkqPZxGS8dExERkQQrmjhNPPrat28fBg0aVPVzYmIiAGDixImYN28eNm7cCADo0aOH3fO+//57DBw4sP49JSIiIiKXUbz28c1+R0REROQSPFPoNL6CRERERKRs7WMAmDdvHtasWYPffvsNOp0OMTExmD9/PmJjY+ucQ9WytbRbsGrcRPFqY7E4h5tJVrtUVSaL17sViOIBQF0iq33so5PXyoSntyjc7BcsincrLxPFA4DNIKuf6+Z1VJzDYjSK4rXHDoniw+rxV+1l/4GieA+NrFYyIP8sSZeBcLOYag+6gV4t249Cq584h0otu8qhEhZYNmvk9XlNZtmxKNN6iXNUWGX/DXhqK0TxOo0sHgA8TEWieDet/D0V5Oknim8e0kwU7+km/+x5CuvGV1jk999XaGTPMVlk78GGxCVpnKdo7WMA6NChA9577z0cPHgQO3bsQGRkJOLi4nDhwgWnO0tERERErqFo7WMAeOSRR+x+XrRoEZYtW4affvoJgwcPlveQiIiIiFzOpWu/VFRU4IMPPoDBYEB0dLQrUxEREdHvGSeaOM0lg8Ivv/wSDz/8MMrKyhAWFobNmzcjMDDQFamIiIiISAEuGRQOGjQIWVlZKCgowIcffogxY8Zgz549CA6uPgHBUe1ja4UZel3jubmViIiIGhgnmjjNJedavby80K5dO9x1111YtmwZtFotli1b5jDWUe3jt/71hSu6RUREREQ1uCUX4K1Wa7Wzgdc4qn08Y9zIW9EtIiIiIvo/itY+DggIwPz583HfffchLCwMBQUFSElJwblz5/DQQw85bM9R7eMrvHRMREREEmpONHGWorWPly5diiNHjmDVqlUoKChAQEAA7rzzTvzwww/o0qWLcr0mIiIiIkUpXvt4/fr1TnWIiIiISIoVTZzHc61ERERE5NrFq4mIiIhuCS5e7TTxoHD79u146623kJmZiZycHKSlpWH06NEOY5955hm8//77eOeddzBt2rQ651BVyIub2zxkk1OKWseIc5xStRPFt42UFVB3qygTxQOAzmIRxZd6h4lz+JWXiuLNeh9Zguay1xUAyrxDRPGGu2WvEwBcCWwlijd9ulIU71lRIYoHAGOfoaL4+hSzD9T7iuKNOoMoPqDotCgeAMwafe1B19Gr5K+tVmUWxZttOlk8ZPEAUHRFtt9tdJfFOVRuNd8O5MgVq7soXquSf/YueTQXxZtt8vd54RVPUfzlYln7piB5n8pMskFNqFeJOIdaZRXFny8Wfp9ToyYeVhuNRkRHRyMlJeWmcWlpadi9ezfCw8Pr3TkiIiIiujXEZwrj4+MRHx9/05hz587hueeew6ZNmzBixIh6d46IiIioLmy8fOw0xV9Bq9WKxx57DDNmzOAyNERERESNhOITTRYuXAitVovnn39e6aaJiIiIHOOSNE5TdFCYmZmJJUuWYP/+/VDV8eCYTKZqJfBsFWboWdWEiIiI6JZR9PLxDz/8gPz8fERERECr1UKr1eLMmTP405/+hMjISIfPSU5OhsFgsNve+uQbJbtFRERERLVQ9EzhY489hiFDhtg9NnToUDz22GOYPHmyw+ckJSVVlcq7xpbxTyW7RURERE0cJ5o4TzwoLC0txfHjx6t+PnXqFLKysuDv74+IiAgEBATYxbu5uSE0NBRRUVEO29Pr9dDr7dfiKuelYyIiIqJbSjwo3LdvHwYNGlT187WzfBMnTsTKlSsV6xgRERFRnXGiidPEg8KBAwfCZqv7CvinT5+WpiAiIiKiW4y1j4mIiKjx4z2FTlO89vGkSZOwatUqu+cMHToU6enpdc5xfs0GabegN3iJ4gMG3CXO0S5KVk/V++huUby1RFhcE4ClRFaXuFlXWX1XAFDlnhXFewbK6nFa9bIapACg8goWxds08vtUpTcte7WLFMWrmwXUHnSDLuqDshzWSnEOj4vnRPGenrJaySqLvE+epkJRvE9lvjiHxiyrPV7uKTt++vJCUTwAqJvJ6gYHnskU5/Dzke2H2V12vLXmK6J4ANAJ34NWnaweMwD4hneX5WjRVhTfCqdE8QDgFhAhivfVyGsfayH7P+CKt6z+NuAtjKfbiUtqHw8bNgw5OTlV27/+9S+nOklEREREruWS2sd6vR6hoaH17hQRERGRhI0TTZzmkgvwGRkZCA4ORlRUFJ599llcvHjRFWmIiIiISCGKTzQZNmwYHnjgAbRu3RonTpzAyy+/jPj4eOzatQsajUbpdEREREScaKIAxQeFDz/8cNW/u3Xrhu7du6Nt27bIyMjA4MGDq8U7qn1sslig5wCSiIiI6JZx+bC6TZs2CAwMtKuCcj1HtY+XHjzh6m4RERER0XVcPig8e/YsLl68iLCwMIe/T0pKQlFRkd32TDfZ1H8iIiL6fbNB1WBbU6Fo7WN/f3+8+uqrePDBBxEaGooTJ07gz3/+M9q1a4ehQ4c6bM9R7eMCXjomIiIiuqUUrX2cmpqKn376CatWrUJhYSHCw8MRFxeH119/vdrAj4iIiEgp0oIDVJ3itY83bdrkVIeIiIiI6NZj7WMiIiJq/Him0Gm35aAw5Oknxc8xe/iJ4g969BDn+DlHlqNjl86ieJ1aXhPWTficIwVB4hxh0bLapZevyG4VCPCU10YtNslyBIW3Eec4XyKr8dq2v2yC1OUKWfsA0HPXm6J4daCsRjQAZLafJIovqdCJ4iP95HWJi80+onijTdYnANDpZHWGy8yyetqBvvI6tbnFBlG8e4ue4hylGj9ZDpusRrTeTRYPAEZP2fdUpUZ+vL3LLojiI729RPGlaCaKB4AT+X6i+IpKeQ5Pfc1X+hzxdZfVSqbGTTys3r59O0aOHInw8HCoVCps2LChWszhw4dx3333wWAwwMvLC3feeSeys7OV6C8RERERuYB4UGg0GhEdHY2UlBSHvz9x4gT69++Pjh07IiMjAz/99BNmz54Nd3d3pztLRERE5IhNpWqwrakQXz6Oj49HfHx8jb9/5ZVXMHz4cLz55n8vc7Vty3UHiYiIiG5nit6VabVa8dVXX6FDhw4YOnQogoODERsb6/ASMxEREZFSbCp1g21NhaJ7kp+fj9LSUixYsADDhg3Dt99+i/vvvx8PPPAAtm3bpmQqIiIiIlKQorOPrVYrAGDUqFGYPn06AKBHjx7YuXMnli5dirvvvrvac0wmE0wmk91jlRVm6HWymX1EREREVH+KnikMDAyEVqtF5872S7F06tSpxtnHycnJMBgMdtvb//hMyW4RERFRU6dSNdzWRCh6plCn0+HOO+/E0aNH7R7/9ddf0apVK4fPSUpKqiqVd03lAVZFISIiIrqVxIPC0tJSHD9+vOrnU6dOISsrC/7+/oiIiMCMGTMwduxYDBgwAIMGDUJ6ejq++OILZGRkOGxPr9dXq4ts5KVjIiIiEmhKEz4ainhQuG/fPgwaNKjq52tn+SZOnIiVK1fi/vvvx9KlS5GcnIznn38eUVFR+Oyzz9C/f3/lek1EREREihIPCgcOHAib7eZlch5//HE8/vjj9e4UEREREd1at2XtYyIiIiIJG5rOhI+GIh4Ubt++HW+99RYyMzORk5ODtLQ0jB49uur3qhpm4bz55puYMWNGnXKojv5H2i3odbKC6J3aFItz+Ed0FcWH5v0kileZK0TxAKCyWkTxzcK7iXN4ll8WxRt9A0TxenOZKB4ACn2CRfHNynPEOXz9QkXxfuW5onh390BRPABAoxGF24wl4hTtVEdrD7pOhZeHKN5mlX9xq92songPrb72oBu4q8pF8Va97P4lf5P8Peju21wUrzFXinOoNDe/8nMj90qjKN6t8oooHgD0xouieJtGfh+6We8tii+3yUq1BljyRPEA0MLPXxRvtcnvofN2k33feqhlnwugpTCebieK1z7Oycmx25YvXw6VSoUHH3zQ6c4SEREROcKKJs4T70l8fDz+8pe/4P7773f4+9DQULvt888/x6BBg9CmTRunO0tERETUFKSkpCAyMhLu7u6IjY3F3r17bxq/ePFiREVFwcPDAy1btsT06dNRXm5/Jlfa5o1cOrzNy8vDV199hSeeeMKVaYiIiOj3rhEtXr127VokJiZi7ty52L9/P6KjozF06FDk5+c7jF+9ejVmzpyJuXPn4vDhw1i2bBnWrl2Ll19+ud5tOuLSQeGqVavg4+ODBx54wJVpiIiIiBqNRYsWYcqUKZg8eTI6d+6MpUuXwtPTE8uXL3cYv3PnTvTr1w+PPPIIIiMjERcXh3HjxtmdCZS26YhLB4XLly/H+PHj4e5e8w26JpMJxcXFdpupHjdLExERETUEh2MZk8lhbEVFBTIzMzFkyJCqx9RqNYYMGYJdu3Y5fE7fvn2RmZlZNQg8efIkvv76awwfPrzebTriskHhDz/8gKNHj+LJJ5+8aZzD2sdf/eCqbhEREVETZIO6wTZHY5nk5GSH/SwoKIDFYkFISIjd4yEhIcjNdbyKxSOPPILXXnsN/fv3h5ubG9q2bYuBAwdWXT6uT5uOuGxQuGzZMsTExCA6OvqmcUlJSSgqKrLbXhzxB1d1i4iIiEhRjsYySUlJirWfkZGBN954A3//+9+xf/9+rF+/Hl999RVef/11xXIALqh9DADFxcX49NNP8de//rXW9hzVPi5z45raREREVHe2ekz4UIqjsUxNAgMDodFokJdnv5ZlXl4eQkMdr487e/ZsPPbYY1VXX7t16waj0YinnnoKr7zySr3adER8pnDfvn3o2bMnevbsCeBq7eOePXtizpw5VTFr1qyBzWbDuHHjpM0TERERNVk6nQ4xMTHYsmVL1WNWqxVbtmxBnz59HD6nrKwMarX9kE3zf8UMbDZbvdp0xCW1j5966ik89dRT0qaJiIiImrzExERMnDgRvXr1Qu/evbF48WIYjUZMnjwZADBhwgQ0b9686r7EkSNHYtGiRejZsydiY2Nx/PhxzJ49GyNHjqwaHNbWZl3wOi0RERE1eo2pssjYsWNx4cIFzJkzB7m5uejRowfS09OrJopkZ2fbnRmcNWsWVCoVZs2ahXPnziEoKAgjR47E/Pnz69xmXahstZ32u0FttY9LS0sxc+ZMbNiwARcvXkTr1q3x/PPP45lnnqlzjrPPjZF0CQCgN3iJ4n0GDRLnyGsVK4oP/m2fKF5lktcIhbC27ZV2d4hTeJyS1aK2+TYTxatkb0EAQHlAhChef/mcOEdJSJQoXius8XrBK1IUDwAVNlmNb4PtkjiHesmc2oOu4xkqq9eqdpPXqdWFympdqw1+4hwwm0Xh1lDZe1B9pVQUDwBFLbuL4g3nfxbnkH6WCr3DRfFaq7ymu1kjqzNshuxzAcg/SycLg0Txg2ybRPEAUOgXKYrXWuSvra5SVvu41F1Wy75VO9n3ppJyjxxosNyhHXs2WG4lKV77ODExEenp6fj4449x+PBhTJs2DVOnTsXGjRud7iwRERGRIzaoGmxrKsSXj+Pj4xEfH1/j73fu3ImJEydi4MCBAK7eX/j+++9j7969uO++++rdUSIiIiJyHcUvwPft2xcbN27EuXPnYLPZ8P333+PXX39FXFyc0qmIiIiIAFy9p7ChtqZC8Ykm7777Lp566im0aNECWq0WarUaH374IQYMGKB0KiIiIiJSiEsGhbt378bGjRvRqlUrbN++HQkJCQgPD7eryXeNyWSqVh/QZLFA/39TrImIiIjI9RQdFF65cgUvv/wy0tLSMGLECABA9+7dkZWVhbffftvhoDA5ORmvvvqq3WPT7+yMxNguSnaNiIiImrCGrGjSVCh6IdxsNsNsNjtcddtqtTp8jqN6gQm9OirZLSIiIiKqheK1j++++27MmDEDHh4eaNWqFbZt24Z//OMfWLRokcP2HNULLOalYyIiIhJoSkvDNBTxoHDfvn0YdN3Cz4mJiQCAiRMnYuXKlVizZg2SkpIwfvx4XLp0Ca1atcL8+fNFi1cTERER0a2leO3j0NBQrFixwqlOEREREdGtxdrHRERE1Og1pfUCGwpfQSIiIiKSnyncvn073nrrLWRmZiInJwdpaWkYPXp01e/z8vLw0ksv4dtvv0VhYSEGDBiAd999F+3bt697p9zlxc31gc1E8VadhzhHucpTFF/pLeyTIUQUDwD6gt9E8ZVaWaF5ALCVFIviVWrhRCEvH1k8gEqtvvag62g95DmK9EGieA9tiSj+stlXFA8AF4xeonhfd/l+33lnN1G8OihUFG/NOSuKBwB1SLgovtIvWJ7DbKo96DrlBtl+u7nL3h8AcFkn+07Q+xeJc1z0jRDFl1tl3506TYUoHgAqhf81mazy/zOMZtl+5BfJvtcs/vLvWpNa1idDsez7HwBUVosoXq+V/1/ZUDjRxHniM4VGoxHR0dFISUmp9jubzYbRo0fj5MmT+Pzzz3HgwAG0atUKQ4YMgdFoVKTDRERERKQ88ZnC+Ph4xMfHO/zdsWPHsHv3bhw6dAhdulxdfDo1NRWhoaH417/+hSeffNK53hIRERE5wHsKnafoK3itXJ27+39Pm6vVauj1euzYsUPJVERERESkIEUHhR07dkRERASSkpJw+fJlVFRUYOHChTh79ixycnKUTEVEREREClJ0SRo3NzesX78eTzzxBPz9/aHRaDBkyBDEx8fXuLahyWSqOsNY9VilBXotq5oQERFR3XCiifMUvwAfExODrKwsFBYWIicnB+np6bh48SLatGnjMD45ORkGg8Fue3fPz0p3i4iIiIhuwmV3ZRoMBgQFBeHYsWPYt28fRo0a5TAuKSkJRUVFdttzsV1c1S0iIiJqgmwqdYNtTYX48nFpaSmOHz9e9fOpU6eQlZUFf39/RERE4NNPP0VQUBAiIiJw8OBBvPDCCxg9ejTi4uIctqfX66HX2685V8ZLx0RERES3lHhQuG/fPgwaNKjq58TERADAxIkTsXLlSuTk5CAxMRF5eXkICwvDhAkTMHv2bOV6TERERESKEw8KBw4cWOOkEQB4/vnn8fzzzzvVKSIiIiIJTjRxXtO5EE5ERERE9SY6U5icnIz169fjyJEj8PDwQN++fbFw4UJERUVVxZSXl+NPf/oT1qxZA5PJhKFDh+Lvf/87QkLqXsPTu3ULSbcAABo/gyi+MKjutZivOVsmq4XrbWgpinevkNdG1frI6isXuctrwnq3bCuKN3vJjoVZL6/Pe9lDVgvXy01WMxgALlT4i+I7WM6L4v095HVqC1Ty/ZBSB8reIxa/QFH8ld17RPEA4KkVXtSoR+1jm0Z2L3OlsCastrJcFA8AKtR8VcYRjfmKOId7pawEabmwPq+1HuceLpT7ieLNVvl96Caz7DnFpbJjYQ7zFsUDQIVNVtP9iqfsswcAamulLIeb/Pu5odhUPFPoLNGnddu2bUhISMDu3buxefNmmM1mxMXF2dU1nj59Or744gt8+umn2LZtG86fP48HHnhA8Y4TERERkXJEf36np6fb/bxy5UoEBwcjMzMTAwYMQFFREZYtW4bVq1fjnnvuAQCsWLECnTp1wu7du3HXXXcp13MiIiKi/2Oz8Uyhs5y6p7Co6OrlL3//q5fZMjMzYTabMWTIkKqYa6Xvdu3a5UwqIiIiInKheg8KrVYrpk2bhn79+qFr164AgNzcXOh0Ovj5+dnFhoSEIDc316mOEhEREZHr1Lv2cUJCAg4dOoQdO3Y41QFHtY/N5kro3RQty0xERERNmI0LqjitXq/g1KlT8eWXX+L7779Hixb/nSkcGhqKiooKFBYW2sXn5eUhNDTUYVuOah//9dvd9ekWEREREdWTaFBos9kwdepUpKWlYevWrWjdurXd72NiYuDm5oYtW7ZUPXb06FFkZ2ejT58+Dtt0VPv4T3GckEJERER1Z4OqwbamQnSNNiEhAatXr8bnn38OHx+fqvsEDQYDPDw8YDAY8MQTTyAxMRH+/v7w9fXFc889hz59+tQ489hR7eNSXjomIiIiuqVEo6/U1FQAV0vdXW/FihWYNGkSAOCdd96BWq3Ggw8+aLd4NRERERHdvkSDwpvVPL7G3d0dKSkpSElJqXeniIiIiCSa0mXchsKpOkRERERU/yVpXMl8WV4TVvqcZp7bxTnuaC3L4X42WxRf6S2rtQsAmrJiUXxw0XFxDtWlfFG8W5mshrP2UoEoHgBaCuvzwiSvO+vVUrbfNrXs46Szyfvko68QxQfq5Z8lm/B4aMpl9XatZrMoHgCMx06J4k37DolzSAXE9hDFq+pxr3RQZ1mdYc0Vef10L7cLonirt6xmsMYiq7ULAB66UlF8pVonzmG0yWoTVzaX1Rn2zj0qigcAdx/ZZ69SJ6+FrjXJXttCd8crh9yOeKbQeaIzhcnJybjzzjvh4+OD4OBgjB49GkeP2r/xP/jgAwwcOBC+vr5QqVTVlqchIiIiotuPaFC4bds2JCQkYPfu3di8eTPMZjPi4uJgNBqrYsrKyjBs2DC8/PLLineWiIiIyBEuSeM80fWM9PR0u59XrlyJ4OBgZGZmYsCAAQCAadOmAQAyMjIU6SARERERuZ5TE02Kiq7er+TvL78XjoiIiIhuH/WeaGK1WjFt2jT069cPXbt2VbJPRERERCI2W9O5jNtQ6j0oTEhIwKFDh7Bjxw6nOmAymWAymewfq7RAr5XNcCMiIiKi+qvX5eOpU6fiyy+/xPfff48WLVo41YHk5GQYDAa77Z1t+51qk4iIiH5fONHEeaJBoc1mw9SpU5GWloatW7eidevWTncgKSkJRUVFdtv0u+9wul0iIiIiqjvR5eOEhASsXr0an3/+OXx8fJCbmwsAMBgM8PC4ushqbm4ucnNzcfz41UWSDx48CB8fH0RERDickKLX66HX6+0es/DSMREREdEtJTpTmJqaiqKiIgwcOBBhYWFV29q1a6tili5dip49e2LKlCkAgAEDBqBnz57YuHGjsj0nIiIi+j+8fOw80ZlCm81Wa8y8efMwb968+vaHiIiIiBrAbVn7mIiIiEiiKZ2xayiiQWFycjLWr1+PI0eOwMPDA3379sXChQsRFRUFALh06RLmzp2Lb7/9FtnZ2QgKCsLo0aPx+uuvw2Aw1DmPxVQh2wsA+gA/UbwporM4xwn37qL4NoGyyd1ac5koHgCsbu6i+HxDO3GO5v7CIu2evqL4igj5Opf5Hq1E8T6Wy+IcZyojRfFh+jxRfL45UBQPAJfL9LUHXcdskS8s3zYgWBRf6R8qive8kC+KBwBtkKxPqv8ckufw8hDF21pHieKtKvl/WDkebUXxrfSXxDmueMjeI4WqAFG8m9YsigeAQrOPKL7SLD+/YbLI7l0/VyCLv9JcPhEzz1P2HJ3KVHvQDVTetV/xu95ls584BzVeitY+Pn/+PM6fP4+3334bhw4dwsqVK5Geno4nnnjCJZ0nIiIiAq4uXt1QW1OhaO3jrl274rPPPqv6fdu2bTF//nw8+uijqKyshFbLq9VEREREtyOX1z4uKiqCr68vB4REREREtzGX1j4uKCjA66+/jqeeeqreHSQiIiKqjZUTTZzmstrHxcXFGDFiBDp37nzTJWpY+5iIiIio4bmk9nFJSQmGDRsGHx8fpKWlwc3Nrca2HNU+XvLv/9SnW0RERPQ7xcWrnad47ePi4mLExcVBp9Nh48aNcHe/+ZIpjmofv9AvWrYXREREROQURWsfXxsQlpWV4eOPP0ZxcTGKi4sBAEFBQdBoql8SdlT7uIKXjomIiIhuKdGgMDU1FQAwcOBAu8dXrFiBSZMmYf/+/dizZw8AoF07+0WST506hcjIyPr3lIiIiKgGTWm9wIaiaO3jgQMH1qk+MhERERHdXrh4IBERETV6TWnCR0NRtPYxADz99NP47rvvcP78eXh7e1fFdOzYsc55zMYrkm4BAFTC+xB1lfKakVp1pShebZHV/FRZZO1ffY4sh7vFKM9RLnuORi07FnqrRRQPAH5aT1G8xxV5TdgAXz9RvLdJVl+5XCertQsABRovUbxOI39PoVL2nlKbhDW7a5l85pBKtlCC1SJ/T5XlXhTFa/btFMW7hYWJ4gHAI0Q26U5bcE6cQ1ZlGCgMChLFayA/Fp4a2fdzhcoqzqFWyc6JeHnU430rJH2tPCuKXdST/6qwymqbU+OmaO1jAIiJicGKFStw+PBhbNq0CTabDXFxcbDU40uaiIiIiG4NRWsfA7CrXhIZGYm//OUviI6OxunTp9G2bVsFukxERERkjxNNnOfS2sdGoxErVqxA69at0bJlS2dSEREREZEL1XtQeLPax3//+9/h7e0Nb29vfPPNN9i8eTN0Op3TnSUiIiJyhBVNnFfvQeG12sdr1qyp9rvx48fjwIED2LZtGzp06IAxY8agvLzcYTsmk6lqketrm6mS9x8SERER3UouqX1sMBjQvn17DBgwAOvWrcORI0eQlpbmsC1HtY/f3ftLfbpFREREv1M2m6rBtqZC8drHjp5js9lgMjleYsBR7ePneneWdIuIiIiInCQaFCYkJODjjz/G6tWrq2of5+bm4sqVq+sKnjx5EsnJycjMzER2djZ27tyJhx56CB4eHhg+fLjDNvV6PXx9fe02PWsfExERUROWkpKCyMhIuLu7IzY2Fnv37q0xduDAgVCpVNW2ESNGVMVMmjSp2u+HDRsm6pOitY/d3d3xww8/YPHixbh8+TJCQkIwYMAA7Ny5E8HBwaKOEREREdWVfAnzhrN27VokJiZi6dKliI2NxeLFizF06FAcPXrU4Xhp/fr1qKioqPr54sWLiI6OxkMPPWQXN2zYMKxYsaLqZ71eL+qXorWPw8PD8fXXX4s6QERERPR7smjRIkyZMgWTJ08GACxduhRfffUVli9fjpkzZ1aLv3HpvzVr1sDT07PaoFCv1yM0tP5VaJxap5CIiIjodtBYJppUVFQgMzMTQ4YMqXpMrVZjyJAh2LVrV53aWLZsGR5++GF4edmXPs3IyEBwcDCioqLw7LPP4uJFWflOWfFHIiIiIrJjMpmqTajV6/UOL98WFBTAYrEgJCTE7vGQkBAcOXKk1lx79+7FoUOHsGzZMrvHhw0bhgceeACtW7fGiRMn8PLLLyM+Ph67du2CRlO3uRqiQWFycjLWr1+PI0eOwMPDA3379sXChQsRFRVVLdZms2H48OFIT09HWloaRo8eXec8nqEBkm4BANyCZUXayz0M4hxllbKC6Fc8HFd6qYnVSz7BxkcjG9eXaJqJc/g1C6k96DomL9nxs6rlf5tc1sruUVV53PzWB0dKK71qD7qOj1Z274bJ5voF3U2V8te2okUHUXypl+z94ad1E8UDQJmP7Hj7esqOHQDYCvJF8RU5ObL2K82ieACwCP9ut3n5inOUe8u+O6WfCze1fL+LKmQ5Kirl352lJtlrezZXtn5uXovaV+e40ZkS2bGI8Hb9eZ2SEhaeqIvk5GS8+uqrdo/NnTsX8+bNUzzXsmXL0K1bN/Tu3dvu8Ycffrjq3926dUP37t3Rtm1bZGRkYPDgwXVqW3T5eNu2bUhISMDu3buxefNmmM1mxMXFwWg0VotdvHgxVKqms3YPERER3b4asqKJo+X1kpKSHPYzMDAQGo0GeXl5do/n5eXVej+g0WjEmjVr8MQTT9T6erRp0waBgYE4fvx4nV9D0Z8Z6enpdj+vXLkSwcHByMzMxIABA6oez8rKwl//+lfs27cPYWFhkhREREREjUpNl4od0el0iImJwZYtW6quolqtVmzZsgVTp0696XM//fRTmEwmPProo7XmOXv2LC5evCgahzk10aSoqAiA/ayYsrIyPPLII0hJSXFqBgwRERFRXTWWiSYAkJiYiA8//BCrVq3C4cOH8eyzz8JoNFbNRp4wYYLDM43Lli3D6NGjERBgf5tWaWkpZsyYgd27d+P06dPYsmULRo0ahXbt2mHo0KF17le9b0iwWq2YNm0a+vXrh65du1Y9Pn36dPTt2xejRo2qb9NERERETdbYsWNx4cIFzJkzB7m5uejRowfS09OrJp9kZ2dDrbY/b3f06FHs2LED3377bbX2NBoNfvrpJ6xatQqFhYUIDw9HXFwcXn/9ddFahfUeFCYkJODQoUPYsWNH1WMbN27E1q1bceDAgTq342jGjqnSwqomREREVGc2NK55DFOnTq3xcnFGRka1x6KiompcL9rDwwObNm1yuk/1unw8depUfPnll/j+++/RokWLqse3bt2KEydOwM/PD1qtFlrt1THngw8+WK0KyjXJyckwGAx226Kt++rTLSIiIiKqJ3FFk+eeew5paWnIyMhA69b2U+5nzpyJJ5980u6xbt264Z133sHIkSMdtpmUlITExES7x8pTqq/mTURERESuIxoUJiQkYPXq1fj888/h4+OD3NxcAIDBYICHhwdCQ0MdTi6JiIioNoC8xtGMHRsvHRMREZGAVb4cLd1AdPk4NTUVRUVFGDhwIMLCwqq2tWvXuqp/RERERHQLiC8fS9XnOUREREQSjW2iye3IqXUKiYiIiKhpULz28cCBA7Ft2za75z399NNYunRpnfNYK2U1JgHAfOGiKN7jwilxjlYtZPWS/c4eFMWrzBWieABA+RVReJhaXndWe+GsKF5jLBTFV/rIa117u/mI4j3KZO8PAAj1lr1WvsXnRPFunqbag25gMMhqV7tXVi9BWRtt3mVRvK+5XBRvq0f5S22lLEd5aDtxDr27rN6uTi3bj5KDh0XxAND8yrLag65jq2PR++t52ayi+MhQWQ5Nhfx7TSN8T1k18u81k6+sTnTLHpGi+LDio6J4AND7yvY76PIxcQ5YZf+/XvIeKEwgPxZ0+3BJ7eMpU6YgJyenanvzzTcV7TQRERHR9RpTRZPblUtqH3t6erLEHREREVEjonjtYwD45z//icDAQHTt2hVJSUkoKytzJg0RERHRTdlsDbc1FYrXPn7kkUfQqlUrhIeH46effsJLL72Eo0ePYv369Yp0mIiIiIiUp2jtYwB46qmnqv7drVs3hIWFYfDgwThx4gTatm1brR3WPiYiIiJnWbkkjdMUrX3sSGxsLADg+PHjDn/vqPbxOxn769MtIiIiIqon0aDQZrNh6tSpSEtLw9atW2ssXXe9rKwsAEBYWJjD3yclJaGoqMhumz7wDkm3iIiIiMhJitY+PnHiBFavXo3hw4cjICAAP/30E6ZPn44BAwage/fuDtt0VPvYwkvHREREJNCUloZpKKJBYWpqKoCrC1Rfb8WKFZg0aRJ0Oh2+++47LF68GEajES1btsSDDz6IWbNmKdZhIiIiIlKeorWPW7ZsWa2aCREREZGrNaWlYRoKax8TERERUf2XpHEldT3uKbRZZPUcVZcLxDl8/HJlOYR1ia3efqJ4AFBrZXUmK/Syep8A4C6sVSut4eyWny2KBwB/S6UoXltySZzDppL9zWTWe4vii/Xyms9WCOvOWs3iHDh2SBSu9ZTVDK68LKutDABaL09RvLqZ/LWV1hFHoKxqk97/vKx9ANZyWS1cTTNZbWwAsAprPht1fqJ4jU32WQWASk+dKN4i/FwAgGdliShep5Z9lvSHdoriASA86KTsCRXy+ukQfj+37hYhTNBNGE+3E9H/esnJybjzzjvh4+OD4OBgjB49GkePVi/6vWvXLtxzzz3w8vKCr68vBgwYgCtXhF+4RERERHVkg6rBtqZCNCjctm0bEhISsHv3bmzevBlmsxlxcXEwGo1VMbt27cKwYcMQFxeHvXv34scff8TUqVOhVvNKNREREdHtSnT5OD093e7nlStXIjg4GJmZmRgwYAAAYPr06Xj++ecxc+bMqrioqCgFukpERETkmJUTTZzm1Om7oqIiAIC/vz8AID8/H3v27EFwcDD69u2LkJAQ3H333dVK4RERERHR7aXeg0Kr1Ypp06ahX79+6Nq1KwDg5MmrN8nOmzcPU6ZMQXp6Ou644w4MHjwYx44dU6bHRERERDew2VQNtjUV9Z59nJCQgEOHDtmdBbRarQCAp59+GpMnTwYA9OzZE1u2bMHy5cuRnJxcrR2TyQSTyX4GlanSAj2rmhARERHdMvU6Uzh16lR8+eWX+P7779GiRYuqx6/VN+7cubNdfKdOnZCd7XjZkeTkZBgMBrtt0dZ99ekWEREREdWTaFBos9kwdepUpKWlYevWrWjdurXd7yMjIxEeHl5tmZpff/0VrVq1cthmUlISioqK7LbEe3oJd4OIiIh+z2y2htuaCtHl44SEBKxevRqff/45fHx8kJt7dTFng8EADw8PqFQqzJgxA3PnzkV0dDR69OiBVatW4ciRI1i3bp3DNvV6PfR6vd1jNl46JiIiIrqlRIPC1NRUAMDAgQPtHl+xYgUmTZoEAJg2bRrKy8sxffp0XLp0CdHR0di8eTPatm2rSIeJiIiIbmRtQotINxTRoNBWx3OkM2fOtFunkIiIiIhubywzQkRERESyM4XJyclYv349jhw5Ag8PD/Tt2xcLFy6sqlhy+vTpapNPrvnkk0/w0EMP1SmPrR7Lkmt9vEXxV9rdIc5x3D1aFN+uuayou760QBQPABatbL/zdC3FOTwDzovirW762oOuU6H3FcUDQIGHbD98m10S58hRtag96Dpty34Sxeus5aJ4ALhgCxHFV7jJ3oMA4NNR9j4v92wmitdWGGsPukGZV6AoXmcqFufQmGT9smncRPG6mN6ieAAoDO8mitd+vEScw/2i7LPh389HFK+ymEXxAHC6WYwo3myVr652piJMFH/krLsovtldD4jiASDfFiqKD7c6XtXjZmwq2bmg/5R2FMU3F0UrqylN+GgoitY+btmyJXJycuy2V199Fd7e3oiPj3fJDhARERGR8xStfazRaBAaav+XTlpaGsaMGQNvb9kZLSIiIqK6akqVRRqKorWPb5SZmYmsrCw88cQTzqQhIiIiIherd5k7R7WPb7Rs2TJ06tQJffv2rXcHiYiIiGpTj+kIdANFax9f78qVK1i9ejVmz55903ZY+5iIiIio4Sla+/h669atQ1lZGSZMmHDTthzVPn7n+8z6dIuIiIiI6knR2sfXW7ZsGe677z4EBQXdtE1HtY+nD5ItR0BERES/b6x97DxFax9fc/z4cWzfvh1ff/11rW06qn1s5aVjIiIioltK8drHALB8+XK0aNECcXFxTneQiIiIqDY21j52mktqH7/xxht444036tUhIiIiIrr1WPuYiIiIiJStfQwAubm5mDFjBjZv3oySkhJERUXhlVdewYMPPljnPO539JJ0CwBg1cnqUv7m2Umc41ieQRSvD5Hl8PUqFMUDgAqyO1zzyvzEOTyDHa9DWZNyq0ftQdepzyn/giuyY2F1l//9U2qSvacu+8hqJRda/UTxAOChltdLljobeqcovkx4vL3VpaJ4ACi1yioiWXTy+5J9/GT9crfKaiW7GUy1B93ghLW9KD46RFYjGgBUatnnT2MslLVfWSGKBwB3f9n7XKuRr67m5Vkme0KLm0+avJG0TjkAHCuQ1RG3+Mvf52pYRfGFZfVeue6W4zqFzlO09jEATJgwAUePHsXGjRtx8OBBPPDAAxgzZgwOHDigeOeJiIiISBmK1j4GgJ07dyI1NRW9e/cGAMyaNQvvvPMOMjMz0bNnT4W6TURERPRfTWlpmIaieO3jvn37Yu3atbh06RKsVivWrFmD8vLyajOWiYiIiOj2oXjt408++QRjx45FQEAAtFotPD09kZaWhnbt2inSYSIiIqIb8Uyh8xSvfTx79mwUFhbiu+++Q2BgIDZs2IAxY8bghx9+QLdu3aq146j2sa3CDL3Orb5dIyIiIiIhRWsfnzhxAu+99x6WL1+OwYMHIzo6GnPnzkWvXr2QkpLisC1HtY/fWvNV/faGiIiIiOpFvHj1c889h7S0NGRkZFSrfVxWdnWKv1ptP9bUaDSwWh1Pg09KSkJiYqJ9nh/WSrpFREREv3NWGyuaOEvR2scdO3ZEu3bt8PTTT+Ptt99GQEAANmzYgM2bN+PLL7902Kaj2sflvHRMREREdEuJLh+npqaiqKgIAwcORFhYWNW2du3VM3tubm74+uuvERQUhJEjR6J79+74xz/+gVWrVmH48OEu2QEiIiIim63htqZC8drH7du3x2effVbvDhERERHRrcfax0RERERU/yVpiIiIiG4XTekybkMRDQqTk5Oxfv16HDlyBB4eHujbty8WLlyIqKioqpgTJ07gxRdfxI4dO2AymTBs2DC8++67CAmpe3Fwq85d0q2rVLKTnm5qsziFt7uskLg0h9pqEcUDgE243xqVbB8AwGKT/e1gscmKtHuqjbUH3cCgd/3fMxWVsv2ogL72oOtUWuX7oNXI3iNaVaU4h4/5kihep/UUxRtKc0TxAOCt9xXFl7nJ4gFAbykTxZs0sv22qmTvJwC4YpS9R9wiWolzwCb7TrAeOyRrvh7/U19pca8ovlL4nQMAbmrZZ0P6fRCsl7/PrQGy73ODtlicw9Mie05A2EVhBhaqaMxE78Bt27YhISEBu3fvxubNm2E2mxEXFwej8ep/6kajEXFxcVCpVNi6dSv+/e9/o6KiAiNHjqxxSRoiIiIiZ1ltDbc1FaI/Q9PT0+1+XrlyJYKDg5GZmYkBAwbg3//+N06fPo0DBw7A1/fqX+qrVq1Cs2bNsHXrVgwZMkS5nhMRERGRYpyaaFJUVAQA8Pf3B3C1ZJ1KpbJbd9Dd3R1qtbpaOTwiIiIiun3Ue1BotVoxbdo09OvXD127dgUA3HXXXfDy8sJLL72EsrIyGI1GvPjii7BYLMjJkd9fQURERFQXNpuqwbamot6DwoSEBBw6dAhr1qypeiwoKAiffvopvvjiC3h7e8NgMKCwsBB33HFHtdJ315hMJhQXF9ttpgr5JBAiIiIiqr96DQqnTp2KL7/8Et9//z1atGhh97u4uDicOHEC+fn5KCgowEcffYRz586hTZs2DttKTk6GwWCw297+5+f16RYRERH9TrGiifPEFU2ee+45pKWlISMjA61bt64xNjAwEACwdetW5Ofn47777nMYl5SUhMTERLvHLHs4KCQiIiK6lUSDwoSEBKxevRqff/45fHx8kJubCwAwGAzw8PAAAKxYsQKdOnVCUFAQdu3ahRdeeAHTp0+3W8vwenq93m5iCgCU6dzqsy9ERET0O9WUloZpKKJBYWpqKgBg4MCBdo+vWLECkyZNAgAcPXoUSUlJuHTpEiIjI/HKK69g+vTpinSWiIiIiFxDfPm4NgsWLMCCBQvq3SEiIiIiuvVY+5iIiIgavaY04aOhiC8fp6am4vTp0wCALl26YM6cOYiPjwcAlJeX409/+hPWrFkDk8mEoUOH4u9//7uo7jEAqM+fEcUDAAzNROG+Fll9VwDwdfcXxXvaSkXx0jrGAOBZUSSKD3AvEefQ266I4kttXqJ4Wz0mwVussjqkHlpZXVsA8NZ5i+K9LLJjUaHRieIBILBStt6nRS3/u69MJ6wzbJUdb5WX/Ju7GH6i+EvlPuIcOmEt3HKT7N5nX73scwQAReWyHMXt7xLnqNDKas0H7NkgircY5bXN253fKoq3usvegwCgNsmOh19YV1G8xiKvO37JJPzudJevj1eukR1vi9WpGhfUyIiOdosWLbBgwQJkZmZi3759uOeeezBq1Cj8/PPPAIDp06fjiy++wKeffopt27bh/PnzeOCBB1zScSIiIqJruCSN80SDwpEjR2L48OFo3749OnTogPnz58Pb2xu7d+9GUVERli1bhkWLFuGee+5BTEwMVqxYgZ07d2L37t2u6j8RERFRo5OSkoLIyEi4u7sjNjYWe/furTF24MCBUKlU1bYRI0ZUxdhsNsyZMwdhYWHw8PDAkCFDcOzYMVGf6n1e2GKxYM2aNTAajejTpw8yMzNhNpsxZMiQqpiOHTsiIiICu3btqm8aIiIioiZl7dq1SExMxNy5c7F//35ER0dj6NChyM/Pdxi/fv165OTkVG2HDh2CRqPBQw89VBXz5ptv4m9/+xuWLl2KPXv2wMvLC0OHDkV5eXmd+yUeFB48eBDe3t7Q6/V45plnkJaWhs6dOyM3Nxc6nQ5+fn528SEhIVXrGRIRERG5gtXWcJvUokWLMGXKFEyePBmdO3fG0qVL4enpieXLlzuM9/f3R2hoaNW2efNmeHp6Vg0KbTYbFi9ejFmzZmHUqFHo3r07/vGPf+D8+fPYsGFDnfslHhRGRUUhKysLe/bswbPPPouJEyfil19+kTZTxWHtY7P8Bl0iIiKi211FRQUyMzPtrqyq1WoMGTKkzldWly1bhocffhheXlcnJ506dQq5ubl2bRoMBsTGxoqu1ooHhTqdDu3atUNMTAySk5MRHR2NJUuWIDQ0FBUVFSgsLLSLz8vLQ2hoaI3tOap9/Nbn30u7RURERL9jDTnRxOEJLpPJYT8LCgpgsViqrcxS1yure/fuxaFDh/Dkk09WPXbtefVt8xqn55pbrVaYTCbExMTAzc0NW7Zsqfrd0aNHkZ2djT59+tT4/KSkJBQVFdltM0YNcrZbRERERLeEoxNcycnJLsm1bNkydOvWDb1791a8bdEiZklJSYiPj0dERARKSkqwevVqZGRkYNOmTTAYDHjiiSeQmJgIf39/+Pr64rnnnkOfPn1w1101r53lqPZxuRvX1CYiIqK6s1obLndSUhISExPtHrtxbHNNYGAgNBoN8vLy7B6v7coqABiNRqxZswavvfaa3ePXnpeXl4ewsDC7Nnv06FHX3ZCdKczPz8eECRMQFRWFwYMH48cff8SmTZtw7733AgDeeecd/PGPf8SDDz6IAQMGIDQ0FOvXr5ekICIiImpU9Ho9fH197baaBoU6nQ4xMTF2V1atViu2bNly0yurAPDpp5/CZDLh0UcftXu8devWCA0NtWuzuLgYe/bsqbXN64lOyS1btuymv3d3d0dKSgpSUlIkzRIRERH9biQmJmLixIno1asXevfujcWLF8NoNGLy5MkAgAkTJqB58+bVLkEvW7YMo0ePRkBAgN3jKpUK06ZNw1/+8he0b98erVu3xuzZsxEeHo7Ro0fXuV+8TktERESNXmOqLDJ27FhcuHABc+bMQW5uLnr06IH09PSqiSLZ2dlQq+0v5h49ehQ7duzAt99+67DNP//5zzAajXjqqadQWFiI/v37Iz09He7udS9tqLLZbr+XsXjRNPFz1HpZHVl1t17iHPnhPUTxgQVHZAlU8jqWGmOhKP5KYKQ4h1t5sSi+zOfm90TcSGtxPEPrZoo8ZPW0AwuPi3OUeofVHnQd71JZXeIyr2BRPAC4X7ksilfZ5DfZVLjLah+btJ6ieLd6HO8ynUEUf8EcJM7hrpH1q8Iqq0scopa9PwCgSCWrtx5WflKco1wnqxMdcGS7LIFRVgMeAEoP/yqK13g4vkx3M/oQ2XvE0i1WFi+sKQ0AJ72iRfF6dYU4h7taVvP5QkVA7UHXuauj7LOqpKWbGiw1nhnacLmVJLqnMDU1Fd27d6+6Xt6nTx988803Vb//4IMPMHDgQPj6+kKlUlVbnoaIiIjIFVj72HmiQWGLFi2wYMECZGZmYt++fbjnnnswatQo/PzzzwCAsrIyDBs2DC+//LJLOktEREREriG6p3DkyJF2P8+fPx+pqanYvXs3unTpgmnTpgEAMjIylOofEREREd0C9Z5oYrFY8Omnn8JoNIqmOxMREREprT41iMmeeFB48OBB9OnTB+Xl5fD29kZaWho6d+7sir4RERER0S0iHhRGRUUhKysLRUVFWLduHSZOnIht27bVe2BoMpmq1Qc0VVZCr+VqOURERFQ3DbuYinz1kNuRuPaxTqdDu3btEBMTg+TkZERHR2PJkiX17oCjeoGLtuyrd3tEREREJCceFN7IarVWO9MnkZSUhKKiIrstcbB8DUEiIiL6/eKSNM4TXaNNSkpCfHw8IiIiUFJSgtWrVyMjIwObNl1dMTI3Nxe5ubk4fvzqQsEHDx6Ej48PIiIi4O/veBFWvV5frT5gMS8dExEREd1SotFXfn4+JkyYgJycHBgMBnTv3h2bNm3CvffeCwBYunQpXn311ar4AQMGAABWrFiBSZMmKddrIiIiIlKUaFC4bNmym/5+3rx5mDdvnjP9ISIiIhKzyqt60g2cvqeQiIiIiBo/0ZnC1NRUpKam4vTp0wCALl26YM6cOYiPj8elS5cwd+5cfPvtt8jOzkZQUBBGjx6N119/HQaDrED27sFviuIBILtAJ4o/frRcnOPwv86I4rveKauQrdXKx+g6new5ez89Ls4R2bGHKL4gt1gUHxjqK4oHgMKLRlF8u06DxTmyTxWJ4sNbdBLFnzl5SRQPAHFDeojiL1wWp8CPu3NE8ZdyLori20d3EMUDwLmTF0Txl/OOinOoVLLPUnmp8D0Y01EUDwDFl0pE8R263SHOkfNboSi+V+z/iuL9msuX6ujWS3a8zVY3cQ4VZLMDfsltJoo/fbZSFA8AW9N+FMX7hweJc2g0GlF8QKjs9Ntd8re5YprShI+GIhoUXqt93L59e9hsNqxatQqjRo3CgQMHYLPZcP78ebz99tvo3Lkzzpw5g2eeeQbnz5/HunXrXNV/IiIiIlKAYrWPn3jiCXz22WdVv2vbti3mz5+PRx99FJWVldByRjERERHRbcultY+Liorg6+vLASERERG5FGsfO89ltY8LCgrw+uuv46mnnlKko0RERETkOi6pfVxcXIwRI0agc+fOtS5R46j2cUWFCjqdvoZnEBEREdnjRBPnKV77uKSkBMOGDYOPjw/S0tLg5nbzWWGOah+vXSaffUxERERE9ef0zX7X1z4uLi7G0KFDodfrsXHjRri7u9f6/KSkJCQmJto9tv2ofAkDIiIi+v2yNehNhU1j3KJY7ePi4mLExcWhrKwMH3/8MYqLi1FcfHW9uqCgoBrXRnJU+1inq6jn7hARERFRfShW+zgjIwN79uwBALRr187ueadOnUJkZKRinSYiIiIiZSlW+3jgwIGw8S5PIiIiagBcksZ5rH1MRERERFDZBKf3blb7GACefvppfPfddzh//jy8vb3Rt29fLFy4EB07yoohFmduEsUDgMoiqzNpcfMQ57jk20oU73slXxRf5BkiigcAN4up9qDrFNiCxTnc1bIcRounKL6ZVl6gt8zqJYr3UcvqMQPAZYus1qleLbsXtqRS9joBQLBbgSheZ7kizmFVyWqjVqpldcfdK2U1g6/mkNW2LVP7iHNoYRbFF1b6ieJD1LKa0gBQqpbVjXeD/H5s6Wep9WVZfV6NqUwUDwDqYlk9bbjJlzAr3rZNFO/ZPFQUr+4qr0N9pnk/UbzJKvvsAYCHulwUf74sUBQ/qJv8/1alLFwnq9OspJf+p2mcYxPtxbXax5mZmdi3bx/uuecejBo1Cj///DMAICYmBitWrMDhw4exadMm2Gw2xMXFwWKxuKTzRERERKQMxWofd+nSxa56SWRkJP7yl78gOjoap0+fRtu2bZXpMREREREpzmW1j41GI1asWIHWrVujZcuWTnWSiIiI6GasnGniNPFF8IMHD8Lb2xt6vR7PPPNMtdrHf//73+Ht7Q1vb29888032Lx5M3Q6+X0PRERERHTriAeF12of79mzB88++ywmTpyIX375per348ePx4EDB7Bt2zZ06NABY8aMQXl5zTe2mkymqoWur22mCi5eTURERHVnszXc1lQoXvvYYDCgffv2GDBgANatW4cjR44gLS2txvYc1T5etGJt/faGiIiIiOpF0drHN7LZbLDZbDX+HnBc+9j0s2ypACIiIvp9a0pn7BqKYrWPT548ibVr1yIuLg5BQUE4e/YsFixYAA8PDwwfPrzGNh3VPi7mPYhEREREt5RitY/Pnz+PH374AYsX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\n",
      "text/plain": [
       "<Figure size 800x800 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(8, 8))\n",
    "\n",
    "sns.heatmap(cos_sim, square=True, cmap='coolwarm')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4f1162c4-e20b-43a6-a06b-4b1e8609146a",
   "metadata": {},
   "source": [
    "从这个图可以看出，并不是对角线是最相似的，有不少片段，都跟开头的两句相似度比较高"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.9"
  },
  "papermill": {
   "default_parameters": {},
   "duration": 1058.563616,
   "end_time": "2024-11-23T14:46:37.625874",
   "environment_variables": {},
   "exception": null,
   "input_path": "13_contextual_embeddings.ipynb",
   "output_path": "run_13_contextual_embeddings.ipynb",
   "parameters": {},
   "start_time": "2024-11-23T14:28:59.062258",
   "version": "2.6.0"
  },
  "widgets": {
   "application/vnd.jupyter.widget-state+json": {
    "state": {
     "0cd8c168767249f2a5fa412173f6e751": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "FloatProgressModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "FloatProgressModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "2.0.0",
       "_view_name": "ProgressView",
       "bar_style": "success",
       "description": "",
       "description_allow_html": false,
       "layout": "IPY_MODEL_5ce1d1d9d86c40d9839877ff95734491",
       "max": 100,
       "min": 0,
       "orientation": "horizontal",
       "style": "IPY_MODEL_231702cf4d79477f9d5548665a1b18fe",
       "tabbable": null,
       "tooltip": null,
       "value": 100
      }
     },
     "2133bb8d85d34b8db112b4408ad60320": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "HTMLStyleModel",
      "state": {
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "HTMLStyleModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "StyleView",
       "background": null,
       "description_width": "",
       "font_size": null,
       "text_color": null
      }
     },
     "231702cf4d79477f9d5548665a1b18fe": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "ProgressStyleModel",
      "state": {
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "ProgressStyleModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "StyleView",
       "bar_color": null,
       "description_width": ""
      }
     },
     "23b1ad9c0f9c46c888da66e85c90eb84": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "2.0.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "2.0.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border_bottom": null,
       "border_left": null,
       "border_right": null,
       "border_top": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "24e6eadc3dc940ecabf30dd1a3c6d1f3": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "FloatProgressModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "FloatProgressModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "2.0.0",
       "_view_name": "ProgressView",
       "bar_style": "success",
       "description": "",
       "description_allow_html": false,
       "layout": "IPY_MODEL_fa4bddf2c33241b5bf918054518f128f",
       "max": 52,
       "min": 0,
       "orientation": "horizontal",
       "style": "IPY_MODEL_edc33e82be8f41eba6a18a0ef074ab7a",
       "tabbable": null,
       "tooltip": null,
       "value": 52
      }
     },
     "2f60367b1c8941e2bf71661c33969ae8": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "2.0.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "2.0.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border_bottom": null,
       "border_left": null,
       "border_right": null,
       "border_top": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "3865f25c78aa46f29a25d807205281c3": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "2.0.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "2.0.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border_bottom": null,
       "border_left": null,
       "border_right": null,
       "border_top": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "3d0b06deaa654b989eece8cde06fa0f8": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "HTMLStyleModel",
      "state": {
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "HTMLStyleModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "StyleView",
       "background": null,
       "description_width": "",
       "font_size": null,
       "text_color": null
      }
     },
     "3f8ceda83287475b97608e42f5f6782f": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "2.0.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "2.0.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border_bottom": null,
       "border_left": null,
       "border_right": null,
       "border_top": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "4881e496f1c84fe29ce9ebebaddfb3c2": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "HBoxModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "HBoxModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "2.0.0",
       "_view_name": "HBoxView",
       "box_style": "",
       "children": [
        "IPY_MODEL_bd096d5d219a467786a85cfe1613fedd",
        "IPY_MODEL_24e6eadc3dc940ecabf30dd1a3c6d1f3",
        "IPY_MODEL_bc2b8104b4244d8cacedeb95e800d91c"
       ],
       "layout": "IPY_MODEL_6b9a8e43c1c342dba500a14e7149b600",
       "tabbable": null,
       "tooltip": null
      }
     },
     "5ce1d1d9d86c40d9839877ff95734491": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "2.0.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "2.0.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border_bottom": null,
       "border_left": null,
       "border_right": null,
       "border_top": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "5ddb08be5cc64c9ab40a1d62a21763a5": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "HTMLModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "HTMLModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "2.0.0",
       "_view_name": "HTMLView",
       "description": "",
       "description_allow_html": false,
       "layout": "IPY_MODEL_86283159049d48b1adcfb2de2d404d4d",
       "placeholder": "​",
       "style": "IPY_MODEL_2133bb8d85d34b8db112b4408ad60320",
       "tabbable": null,
       "tooltip": null,
       "value": " 100/100 [08:34&lt;00:00, 10.01s/it]"
      }
     },
     "5ef9d83ccad1471f85335900a24a8553": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "2.0.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "2.0.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border_bottom": null,
       "border_left": null,
       "border_right": null,
       "border_top": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "6b9a8e43c1c342dba500a14e7149b600": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "2.0.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "2.0.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border_bottom": null,
       "border_left": null,
       "border_right": null,
       "border_top": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "816a079a8c804fbfa9b9a74f941abea8": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "HBoxModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "HBoxModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "2.0.0",
       "_view_name": "HBoxView",
       "box_style": "",
       "children": [
        "IPY_MODEL_bcc69ec5db1b4aab977807284c9290e7",
        "IPY_MODEL_0cd8c168767249f2a5fa412173f6e751",
        "IPY_MODEL_5ddb08be5cc64c9ab40a1d62a21763a5"
       ],
       "layout": "IPY_MODEL_d1178c6858284f788a80b5f2a14fd0b7",
       "tabbable": null,
       "tooltip": null
      }
     },
     "86283159049d48b1adcfb2de2d404d4d": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "2.0.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "2.0.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border_bottom": null,
       "border_left": null,
       "border_right": null,
       "border_top": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "8ff8262c56604119883f4a5f13bb74ab": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "HTMLModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "HTMLModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "2.0.0",
       "_view_name": "HTMLView",
       "description": "",
       "description_allow_html": false,
       "layout": "IPY_MODEL_5ef9d83ccad1471f85335900a24a8553",
       "placeholder": "​",
       "style": "IPY_MODEL_e89e77133c344fc48c1d62f5a607ec93",
       "tabbable": null,
       "tooltip": null,
       "value": " 8/8 [00:18&lt;00:00,  2.27s/it]"
      }
     },
     "9189a076554543aaa6f5ee04e40dbe1b": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "HTMLStyleModel",
      "state": {
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "HTMLStyleModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "StyleView",
       "background": null,
       "description_width": "",
       "font_size": null,
       "text_color": null
      }
     },
     "988e6697a2af486fadeaf0b84347b565": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "HBoxModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "HBoxModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "2.0.0",
       "_view_name": "HBoxView",
       "box_style": "",
       "children": [
        "IPY_MODEL_e1aae4c55cb64f379e74f15357275628",
        "IPY_MODEL_fd9e23198ca1489a9773fda3510bf857",
        "IPY_MODEL_8ff8262c56604119883f4a5f13bb74ab"
       ],
       "layout": "IPY_MODEL_d2ee15001d2244529f7e47d3333c0f8e",
       "tabbable": null,
       "tooltip": null
      }
     },
     "9fc7d91f94a94933bde5ba80e64587de": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "HTMLStyleModel",
      "state": {
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "HTMLStyleModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "StyleView",
       "background": null,
       "description_width": "",
       "font_size": null,
       "text_color": null
      }
     },
     "a7d240a289084bdfba4724c0efd5ab07": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "ProgressStyleModel",
      "state": {
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "ProgressStyleModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "StyleView",
       "bar_color": null,
       "description_width": ""
      }
     },
     "bc2b8104b4244d8cacedeb95e800d91c": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "HTMLModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "HTMLModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "2.0.0",
       "_view_name": "HTMLView",
       "description": "",
       "description_allow_html": false,
       "layout": "IPY_MODEL_2f60367b1c8941e2bf71661c33969ae8",
       "placeholder": "​",
       "style": "IPY_MODEL_9fc7d91f94a94933bde5ba80e64587de",
       "tabbable": null,
       "tooltip": null,
       "value": " 52/52 [04:26&lt;00:00,  4.22s/it]"
      }
     },
     "bcc69ec5db1b4aab977807284c9290e7": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "HTMLModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "HTMLModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "2.0.0",
       "_view_name": "HTMLView",
       "description": "",
       "description_allow_html": false,
       "layout": "IPY_MODEL_3f8ceda83287475b97608e42f5f6782f",
       "placeholder": "​",
       "style": "IPY_MODEL_3d0b06deaa654b989eece8cde06fa0f8",
       "tabbable": null,
       "tooltip": null,
       "value": "100%"
      }
     },
     "bd096d5d219a467786a85cfe1613fedd": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "HTMLModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "HTMLModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "2.0.0",
       "_view_name": "HTMLView",
       "description": "",
       "description_allow_html": false,
       "layout": "IPY_MODEL_3865f25c78aa46f29a25d807205281c3",
       "placeholder": "​",
       "style": "IPY_MODEL_9189a076554543aaa6f5ee04e40dbe1b",
       "tabbable": null,
       "tooltip": null,
       "value": "100%"
      }
     },
     "cc3ed8dc4a5c43aca7b62d904865b2fa": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "2.0.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "2.0.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border_bottom": null,
       "border_left": null,
       "border_right": null,
       "border_top": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "cf68b6fe24964ce792aa63827489cb97": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "HTMLStyleModel",
      "state": {
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "HTMLStyleModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "StyleView",
       "background": null,
       "description_width": "",
       "font_size": null,
       "text_color": null
      }
     },
     "d1178c6858284f788a80b5f2a14fd0b7": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "2.0.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "2.0.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border_bottom": null,
       "border_left": null,
       "border_right": null,
       "border_top": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "d2ee15001d2244529f7e47d3333c0f8e": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "2.0.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "2.0.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border_bottom": null,
       "border_left": null,
       "border_right": null,
       "border_top": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "e1aae4c55cb64f379e74f15357275628": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "HTMLModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "HTMLModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "2.0.0",
       "_view_name": "HTMLView",
       "description": "",
       "description_allow_html": false,
       "layout": "IPY_MODEL_23b1ad9c0f9c46c888da66e85c90eb84",
       "placeholder": "​",
       "style": "IPY_MODEL_cf68b6fe24964ce792aa63827489cb97",
       "tabbable": null,
       "tooltip": null,
       "value": "100%"
      }
     },
     "e89e77133c344fc48c1d62f5a607ec93": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "HTMLStyleModel",
      "state": {
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "HTMLStyleModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "StyleView",
       "background": null,
       "description_width": "",
       "font_size": null,
       "text_color": null
      }
     },
     "edc33e82be8f41eba6a18a0ef074ab7a": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "ProgressStyleModel",
      "state": {
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "ProgressStyleModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "StyleView",
       "bar_color": null,
       "description_width": ""
      }
     },
     "fa4bddf2c33241b5bf918054518f128f": {
      "model_module": "@jupyter-widgets/base",
      "model_module_version": "2.0.0",
      "model_name": "LayoutModel",
      "state": {
       "_model_module": "@jupyter-widgets/base",
       "_model_module_version": "2.0.0",
       "_model_name": "LayoutModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/base",
       "_view_module_version": "2.0.0",
       "_view_name": "LayoutView",
       "align_content": null,
       "align_items": null,
       "align_self": null,
       "border_bottom": null,
       "border_left": null,
       "border_right": null,
       "border_top": null,
       "bottom": null,
       "display": null,
       "flex": null,
       "flex_flow": null,
       "grid_area": null,
       "grid_auto_columns": null,
       "grid_auto_flow": null,
       "grid_auto_rows": null,
       "grid_column": null,
       "grid_gap": null,
       "grid_row": null,
       "grid_template_areas": null,
       "grid_template_columns": null,
       "grid_template_rows": null,
       "height": null,
       "justify_content": null,
       "justify_items": null,
       "left": null,
       "margin": null,
       "max_height": null,
       "max_width": null,
       "min_height": null,
       "min_width": null,
       "object_fit": null,
       "object_position": null,
       "order": null,
       "overflow": null,
       "padding": null,
       "right": null,
       "top": null,
       "visibility": null,
       "width": null
      }
     },
     "fd9e23198ca1489a9773fda3510bf857": {
      "model_module": "@jupyter-widgets/controls",
      "model_module_version": "2.0.0",
      "model_name": "FloatProgressModel",
      "state": {
       "_dom_classes": [],
       "_model_module": "@jupyter-widgets/controls",
       "_model_module_version": "2.0.0",
       "_model_name": "FloatProgressModel",
       "_view_count": null,
       "_view_module": "@jupyter-widgets/controls",
       "_view_module_version": "2.0.0",
       "_view_name": "ProgressView",
       "bar_style": "success",
       "description": "",
       "description_allow_html": false,
       "layout": "IPY_MODEL_cc3ed8dc4a5c43aca7b62d904865b2fa",
       "max": 8,
       "min": 0,
       "orientation": "horizontal",
       "style": "IPY_MODEL_a7d240a289084bdfba4724c0efd5ab07",
       "tabbable": null,
       "tooltip": null,
       "value": 8
      }
     }
    },
    "version_major": 2,
    "version_minor": 0
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
